Classes with the same name - are they limited only within one translation unit?

Let me have the following code:

foo.h

class Foo { // ... }; 

foo.cpp

 #include "foo.h" // Functions for class Foo defined here... 

Let's say that Foo are built into the static library foo.lib .

Now let's say that I have the following:

foo2.h

 class Foo { // ... }; 

foo2.cpp

 #include "foo2.h" // Functions for class Foo defined here... 

It is built into a separate static library foo2.lib .

Now, if I re-bind foo.lib and foo2.lib to the foo.exe , should it complain that class Foo was defined twice?

In my experiments, neither the compiler nor the linker complain.

I would not expect the compiler to complain because they were defined in separate translation units.

But why is the complainant not complaining?

How does the linker distinguish between 2 versions of the Foo class? Does this work by decorating characters?

+4
source share
6 answers

You may have several class type definitions in several translation units, subject to some fairly strong restrictions, which means that the definitions should be almost identical. (3.2 [basic.def.odr])

This also applies to enumeration types, built-in functions with external communication, a class template, a non-static function template, a static data element of a class template, a member function of a class template, or a template specialization for which some template parameters are not specified.

This effectively means that you can follow the usual practice of putting the class definition in the header file and use it in several translation units, if there is no difference in the sequence included, which will lead to a sequence of markers or the value of any names used in the class definition differ between several translation units.

What you cannot have is more than one definition of a non-built-in member function of a class in an entire program.

Violations of any of these rules lead to undefined behavior, so no part of the compilation sequence is required to create diagnostics or any specific behavior, therefore, if you have two class definitions that are slightly different from each other, or can cause strange problems at runtime.

It is very likely that if you have two definitions of the function of a non-inline member of an identically named class with the same signature and that you will have errors during the link, but this is not a guarantee of the language.

It is worth noting that if two definitions for the same objects are in separate object files in libraries (identical or difference libraries), it is likely that your program will not actually include more than one definition for this object. How linkers traditionally work is that iteratively select object files that help resolve characters in a program, but they don't contain object files that don't help resolve characters. This means that after including the first object file with the definition, there is no need to include the second object file with an alternative definition.

+2
source

No, neither the compiler nor the linker should complain. They could; but it is not required.
See One Definition Rule .

+2
source

To make this generate a linker error, you need to force a character with an external link to be shared between the two versions of foo - and both of these characters should be used. Since the only class characters that can be externally linked are member functions, you must have a non-built-in function in every Foo with the same name.

Bottom line: it may or may not work, and you wonโ€™t recognize a single case until you try (because you cannot force the compiler to embed functions). Do not do this.

For example, in the following code, you will get the repeatedly defined Foo::Foo at link-time:

foo.h

 class Foo { public: Foo(); int a; }; 

foo2.h

 class Foo { public: Foo(); int b; }; 

foo.cpp

 #include "foo.h" #include <cstdio> Foo::Foo() : a(22) {} void do_foo() { Foo foo; std::printf("%d\n", foo.a); } 

foo2.cpp

 #include "foo2.h" #include <cstdio> Foo::Foo() : b(33) {} void do_foo_2() { Foo foo; printf("%d\n", foo.b); } 

main.cpp

 extern void do_foo(); extern void do_foo_2(); int main(int argc, char** argv) { do_foo(); do_foo_2(); } 
+2
source

Part of the problem is that each class is in a static library. Linkers specially process static libraries and extract only the necessary objects to satisfy missing bound symbols.

Whether you get a communication error or not will depend on what characters each foo implementation has and how they are packed together. Since you have simple packaging (one .cpp file for each foo, which contains all the methods), it is easy to create a conflict.

So, create a situation when you come across a conflict. You want to define one foo as follows:

 class foo { public: foo(); int a() const; }; 

and your second foo like this:

 class foo { public: foo(); int b() const; }; 

Now each of these foo has one identical character with a binding for the default constructor and the second other character.

Now in your application there is one function in one file that does:

 int lib1() { foo f; return fa(); } 

and the second file that does this:

 int lib2() { foo f; return fb(); } 

Your application will now have the three characters it needs, foo::foo , foo::a and foo::b . Due to foo::a and foo::b , the linker will try to use both static libraries, but then it will pull out two different copies of foo::foo , which will cause a linker error.

+1
source

You must include one of these foo headers. The compiler will only know about the included Foo class, and perhaps due to name mangling the linker cannot complain either.

On the other hand, if you include both headers, the compiler must complain, and the linker may still complain.

0
source

I believe that the compiler should complain to the linker. Let me explain better.

  • The compiler perfectly compiles the compilation of two separate blocks, as expected.
  • When the compiler receives a new file referencing "foo.h" and "foo2.h" (according to Andreas's example), there should be an immediate name conflict.

If two libraries are referenced separately (there are no links to the source / header file and dependencies), it is possible that the program compiles and links correctly due to a name change, but I'm not sure about that.

@Igor (I canโ€™t comment ... duh!) On the page where you talk about ODR, it says that you are exactly the opposite of what you indicated (see. The first example). You can have several objects with the same name and several definitions only by special rules. The number of ads also depends on the type of object.

0
source

Source: https://habr.com/ru/post/1309515/


All Articles