Same Class Name in Different C++ Files

Same class name in different C++ files

This is a violation of the one definition rule (C++03, 3.2/5 "One definition rule"), which says (among other things):

There can be more than one definition of a class type (clause 9), ...
in a program provided that each definition appears in a different
translation unit, and provided the definitions satisfy the following
requirements. Given such an entity named D defined in more than one
translation unit, then

  • each definition of D shall consist of the same sequence of tokens;

If you violate the one definition rule, the behavior is undefined (which means that strange things can happen).

The linker sees multiple definitions of Student::foo() - one in a's object file and one in b's. However it doesn't complain about this; it just selects one of the two (as it happens, the first one it comes across). This 'soft' handling of duplicate functions apparently happens only for inline functions. For non-inline functions, the linker will complain about multiple definitions and will refuse to produce an executable (there may be options that relax this restriction). Both GNU ld and MSVC's linker behave this way.

The behavior makes some sense; inline functions need to be available in every translation unit they're used in. And in the general case they need to have non-inline versions available (in case the call isn't inlined or if the function's address is taken). inline is really just a free pass around the one-definition rule - but for it to work, all the inline definitions need to be the same.

When I look at dumps of the object files, I don't see anything obvious that explains to me how the linker knows that one function is permitted to have multiple definitions and others aren't, but I'm sure there's some flag or record which does just that. Unfortunately, I find that the workings of the linker and object file details aren't particularly well documented, so the precise mechanism will probably remain a mystery to me.

As for your second question:

As an extra question, if classes are defined in header files, should
they always be wrapped with unnamed namespace to avoid such situation?
Is there any side effects?

You almost certainly don't want to do this each class would be a distinct type in each translation unit, so technically instances of the class they couldn't be passed from one translation unit to another (by pointer, reference or copying). Also, you'd end up with multiple instances of any static members. That probably wouldn't work well.

Put them in different, named namespaces.

C++/VS2005: Defining the same class name in two different .cpp files

Try sticking the classes in an anonymous namespace, you may find it less distasteful than having to create and name a new namespace for each file.

Don't have access to VS2005 and Cpp unit but this may work..

//Tests1.cpp
namespace
{
struct MyFixture { MyFixture() { ... do some setup things ...} };
}

TEST_FIXTURE(MyFixture, SomeTest)
{
...
}

//Tests2.cpp
namespace
{
struct MyFixture { MyFixture() { ... do some other setup things, different from Tests1}};
}

TEST_FIXTURE(MyFixture, SomeOtherTest)
{
...
}

C++ Multiple classes with same name

The standard way around this problem is to wrap the classes in different namespaces.

Why does the same class being defined in multiple .cpp files not cause a linker multiple definition error?

You're thinking of the one definition rule. I'm quoting from there (boldface is emphasis of my choosing, not a part of the original document).

Your understanding would be correct--it's illegal to define the same function in multiple compilation units:

One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.

However, this isn't the case for classes, which can be defined multiple times (up to once in each compilation unit), as long as the definitions are all identical. If they are identical, then you can safely pass instances of that class from one compilation unit to another, since all compilation units have compatible, identical definitions with compatible sizes and memory layouts.

Only one definition of any variable, function, class type, enumeration type, concept (since C++20) or template is allowed in any one translation unit (some of these may have multiple declarations, but only one definition is allowed).

...

There can be more than one definition in a program, as long as each definition appears in a different translation unit, of each of the following: class type, enumeration type, inline function with external linkage inline variable with external linkage (since C++17), class template, non-static function template, static data member of a class template, member function of a class template, partial template specialization, concept, (since C++20) as long as all of the following is true:

  • each definition consists of the same sequence of tokens (typically, appears in the same header file)
  • name lookup from within each definition finds the same entities (after overload-resolution), except that constants with internal or no linkage may refer to different objects as long as they are not ODR-used and have the same values in every definition.
  • overloaded operators, including conversion, allocation, and deallocation functions refer to the same function from each definition (unless referring to one defined within the definition)
    the language linkage is the same (e.g. the include file isn't inside an extern "C" block)
  • the three rules above apply to every default argument used in each definition
  • if the definition is for a class with an implicitly-declared constructor, every translation unit where it is odr-used must call the same constructor for the base and members
  • if the definition is for a template, then all these requirements apply to both names at the point of definition and dependent names at the point of instantiation

If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the behavior is undefined.

The bullet points are a fancy and highly precise way of specifying that the definitions must be the same, in letter and in effective result.

Same class in multiple files

The instance of player on path_one.cpp is local and it will be seen only in this function.

To all path_one calls see the same Player instance, you need to pass it by reference:

void path_one(Player& player) {
printf("\n\nYour Health is: %d", player.health);
}

You can create a singleton that is nothing more than a static instance of Player, but it is not recommended because in the end of day, singleton create unnecessarily structure to global variables and functions that you can better replace with namespaces definitions. Will get a more clear, simple and better code.

C++ Multiple Libraries Define Same Class Name

As a solution was never proposed, I'm posting an answer that summarizes my research and my ultimate resolution. Mostly, I encourage the use of namespaces, because proper uses of namespaces would have eliminated the conflict. However, Arduino environments try to keep things simple to lower the barrier of entry, eschewing "complicated" features of C++, so more advanced use cases will likely continue to run into issues like this. From other SO answers and forum posts (cited where I could), here are some methods for avoiding name conflicts like this:

If you can edit the source

Edit the source code to remove the conflict or add a namespace to one of both libraries. If this is an open source library, submit a pull request. This is the cleanest solution. However, if you can't push your changes back upstream (such as when one is a system library for some hardware), you may end up with merge issues down the road when the maintainer/developer updates the libraries.

If you can't edit the source

Credit for part of this: How to avoid variable/function conflicts from two libraries in C++

For libraries that are header only libraries (or all functions are inline)

(ie, they have only a .h file without a .o or .cpp)

Include the library inside a namespace. In most code, this is frowned upon as poor form, but if you're already in a situation where you are trying to cope with a library that doesn't contain itself nicely, it's a clean and simple way to contain the code in a namespace and avoid name conflicts.

main.cpp

namespace foo {
#include library.h
}

int main() {
foo::bar(1);
}

For libraries with functions

The above method will fail to link at compile time, because the declarations in the header will be inside the namespace, but the definitions of those functions are not.

Instead, create a wrapper header and implementation file. In the header, declare your namespace and functions you wish to use, but do not import the original library. In the implementation file, import your library, and use the functions inside your new namespaced functions. That way, the one conflicting library is not imported into the same place as the other.

wrapper.h

namespace foo {
int bar(int a);
}

wrapper.cpp

#include "wrapper.h"
#include "library.h"

namespace foo {
int bar(int a) {
return ::bar(a);
}
}

main.cpp

#include "wrapper.h"

int main() {
foo::bar(1);
}

You could also, for the sake of consistency, wrap both libraries so they're each in their own namespace. This method does mean that you will have to put in the effort to write a wrapper for every function you plan to use. This gets more complicated, however, when you need to use classes from the library (see below).

For libraries with classes

This is an extension of the wrapper function model from above, but you will need to put in more work, and there are a few more drawbacks. You can't write a class that inherits from the library's class, as that would require importing the original library in your wrapper header prior to defining your class, so you must write a complete wrapper class. You also cannot have a private member of your class of the type from the original class that you can delegate calls to for the same reason. The attempt at using a forward declaration I described in my question also did not work, as the header file needs a complete declaration of the class to compile. This left me the below implementation, which only works in the cases of a singleton (which was my use case anyway).

The wrapper header file should almost completely duplicate the public interface of the class you want to use.

wrapper.h

namespace foo {
Class Bar() {
public:
void f(int a);
bool g(char* b, int c, bool d);
char* h();
};
}

The wrapper implementation file then creates an instance and passes the calls along.

wrapper.cpp

#include "wrapper.h"
#include "library.h"

namespace foo {

::Bar obj;

void Bar::f(int a) {
return obj.f(a);
}

bool Bar::g(char* b, int c, bool d) {
return obj.g(b, c, d);
}

char* Bar::h() {
return obj.h();
}
}

The main file will interact with only a single instance of the original class, no matter how many times your wrapper class in instantiated.

main.cpp

#include "wrapper.h"

int main() {
foo::Bar obj;
obj.f(1);
obj.g("hello",5,true);
obj.h();
}

Overall, this strikes me as a flawed solution. To fully wrap this class, I think the this could be modified to add a factory class that would be fully contained inside the wrapper implementation file. This class would instantiate the original library class every time your wrapper class is instantiated, and then track these instances. In this way, your wrapper class could keep an index to its associated instance in the factory and bypass the need to have that instance as its own private member. This seemed like a significant amount of work, and I did not attempt to do so, but would look something like the code below. (This probably needs some polish and a real look at its memory usage!)

The wrapper header file adds a constructor & private member to store an instance id

wrapper.h

namespace foo {
Class Bar() {
public:
Bar();
void f(int a);
bool g(char* b, int c, bool d);
char* h();
private:
unsigned int instance;
};
}

The wrapper implementation file then adds a factory class to manage instances of the original library's class

wrapper.cpp

#include "wrapper.h"
#include "library.h"

namespace foo {

class BarFactory {
public:
static unsigned int new() {
instances[count] = new ::Bar();
return count++;
}
static ::Bar* get(unsigned int i) {
return instances[i];
}
private:
BarFactory();
::Bar* instances[MAX_COUNT]
int count;
};

void Bar::Bar() {
instance = BarFactory.new();
}

void Bar::f(int a) {
return BarFactory.get(i)->f(a);
}

bool Bar::g(char* b, int c, bool d) {
return BarFactory.get(i)->g(b, c, d);
}

char* Bar::h() {
return BarFactory.get(i)->h();
}
}

The main file remains unchanged

main.cpp

#include "wrapper.h"

int main() {
foo::bar obj;
obj.f(1);
obj.g("hello",5,true);
obj.h();
}

If all of this seems like a lot of work, then you're thinking the same thing I did. I implemented the basic class wrapper, and realized it wasn't going to work for my use case. And given the hardware limitations of the Arduino, I ultimately decided that rather than add more code to be able to use the HTTPClient implementation in either library, I wrote my own HTTP implementation library in the end, and so used none of the above and saved several hundred kilobytes of memory. But I wanted to share here in case somebody else was looking to answer the same question!



Related Topics



Leave a reply



Submit