Why doesn't class definition in cpp files cause linker error?

If I have a foo.cpp file with the following code:

 class Foo { }; class Foo { }; int main() { return 0; } 

Then, of course, I get error: redefinition of 'Foo' . However, if I have foo.cpp with

 class Foo { }; int main() { return 0; } 

And bar.cpp with

 class Foo { }; 

Despite the fact that class Foo is defined twice in the program, all this compiles fine.

If I put int something; into both files in the global namespace, then I would get a linker error (in particular, duplicate symbol ), but this will never happen to define classes.

I know that function declarations such as int doIt(); can be duplicated in both cpp files, but the definition, for example. int doIt() {} cannot be. Now in the first compiler error (with class Foo{}; twice in the same cpp file), he said redefinition of foo , so class Foo{}; is a definition. Then why, unlike functions, can this be determined twice in one program?

EDIT: According to this website , the named classes have an external link. So, why is there no collision between class Foo for both cpp files?

EDIT2:. According to the website above, not only classes with named external links, but also static members. But all this compiles fine:

foo.cpp :

 class Foo { public: int foo(); static int x; }; int Foo::foo() { return 5; } int main() { return 0; } 

bar.cpp :

 class Foo { public: int foo(int); static bool x; }; int Foo::foo(int i) { return i * 2; } 

Not only overriding Foo::foo with a different signature, but Foo::x has a different type. Both of them must have an external connection, but this code is A-ok.

+7
c ++ class c ++ 11 linker
source share
4 answers

Regarding your first question, with identical definitions in several TUs that are explicitly resolved by ODR, because otherwise the language would be useless.

Regarding the second question, with different definitions in different TUs, which is a violation of ODR. However, this is NDR. Your program is still garbled, and this is likely to cause strange errors.

Regarding the third question, with static data members, these are declarations, not definitions. They need a unique definition, for example:

 TheType ClassName::VariableName; 

They are usually placed in the accompanying .cpp file.

There is an exception to this, with const static data elements with inline initializers.


ODR = one definition rule
TU = translation unit
NDR = No Diagnostics Required

a note on the PDR; for the compiler, errors are difficult to detect, and the standard usually does not require the compiler to issue diagnostics (i.e. a warning or error) in these cases. There are tools like CppLint that can detect many errors in the compiler I can’t. When it comes to ODR violations, they can usually be avoided only by defining types in the headers.

+2
source share

Due to " One Rule of Definition " in C ++. You cannot redefine a class within a single translation unit, but a class can (and should be) defined in each translation unit that uses it. Therefore, headers and #include exist in C / C ++. You should put the class definition in the header and include it in every .cpp that uses it. This prevents ODR from breaking, but technically using #include matches the class definition in each .cpp file (the preprocessor just makes the included file part of the compiled file).

Also note how definition is different from declaration in C ++.

Update . In your new example with static member variables, you have declarations without a definition :

 class Foo { public: static int x; // <-- variable declaration }; int Foo::x; // <-- variable definition 

You can duplicate ads within a translation unit, but not define.

The definition of types (including classes) can be duplicated in different translation units, functions and variables with external communication - not.

Defining two types in two translation units with the same name but with a different structure is an ODR violation that linkers usually cannot diagnose - your program is incorrect, but everything “builds just fine”.

A translation unit is what the compiler receives as input after preprocessing. Using clang or gcc, you can do it like this:

 $ clang -E foo.cpp >foo.ii 
+1
source share

Each cpp file independently compiles all the definitions. Their difference from the perspective of the compiler from defining it twice in two different cpp files or once in shared include.

The definition of the class in it itself does not introduce any user-defined characters and, therefore, will not lead to a linker error. Only class methods and static members are used. If methods are defined in the class definition, they are considered as built-in. The built-in functions are marked so that the linker selects any available definition and assume that it is equivalent to everything else. If these methods are not defined in the class definition and are not marked on the line, multiple instances will result in a linker error.

0
source share

Typically, classes are defined in header files, and if you do this, then you will get errors when including the header file.

-one
source share

All Articles