If I have a file foo.cpp
with the following code:
class Foo {
};
class Foo {
};
int main() {
return 0;
}
Then naturally 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 class Foo
being defined twice across the program, this whole thing compiles fine.
If I had put int something;
in both files in global namespace, then I would've gotten a linker error (specifically duplicate symbol
), but for class definitions, this never happens.
I know function declarations such as int doIt();
can be duplicated in both cpp files, but a definition, e.g. int doIt() {}
cannot be. Now in the first compiler error (with class Foo{};
twice in one cpp file), it said redefinition of foo
, so class Foo{};
is a definition. Then why, unlike functions, can it be defined twice in one program?
EDIT: According to this website, named classes have external linkage. So why then is there no clash between class Foo
across both cpp files?
EDIT2: According to the website linked above, not only do named classes have external linkage, but so do it's static members. Yet this all 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 has Foo::foo
been redefined with a different signature, but Foo::x
is of a different type. Both of these should have external linkage yet this code is A-ok.
Regarding your first question, with identical definitions across multiple TU's, that's explicitly allowed by ODR, because otherwise the language would be useless.
Regarding the second question, with different definitions in different TU's, that is an ODR-violation. However, those are NDR. Your program is still malformed, and it will probably cause weird errors.
Regarding the third question, with static
data members, those are
declarations, not definitions. They need an unique definition, like:
TheType ClassName::VariableName;
Those are typically placed in the accompanying .cpp file.
There is an exception to that, with const
static
data members with
inline initializers.
ODR = One Definition Rule
TU = Translation Unit
NDR = No Diagnostic Required
A note regarding NDR; some kind of errors are hard for the compiler to detect, and the standard usually do not require that the compiler issue a diagnostic (ie warning or error) in those cases. There are tools, such as CppLint, that can detect many of the errors the compiler can not. When it comes to ODR-violations, those can usually be avoided by only define types in headers.
Because of "One Definition Rule" in C++. You can't redefine class within one translation unit, but class can (and should be) defined in each translation unit which uses it. That's why headers and #include exist in C/C++. You should place class definition in header and include it to each .cpp which uses it. It prevents ODR violation but technically using #include is the same as definition the class in each .cpp file (preprocessor just makes the included file a part of compiled file).
Also pay attention to how definition
differs from declaration
in C++.
Upd. In your new example with static member variables you have only declarations without definition:
class Foo {
public:
static int x; // <-- variable declaration
};
int Foo::x; // <-- variable definition
One can duplicate declarations within translation unit but not definitions.
Definition of types (including classes) can be duplicated in different translation units, functions and variables with external linkage - not.
Definition of two types in two translation units with the same name but different structure is ODR violation which linkers usually can't diagnose - your program is incorrect but all "builds just fine".
Translation unit is what the compiler get as an input after preprocessing. Using clang or gcc you can get it like this:
$ clang -E foo.cpp >foo.ii
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With