The One Definition Rule (ODR) is an important rule of the C++ programming language that prescribes that classes/structs and non-inline functions cannot have more than one definition in the entire program and templates and types cannot have more than one definition by translation unit. It is defined in the ISO C++ Standard (ISO/IEC 14882) 2003, at section 3.2. Some other programming languages have similar but differently defined rules towards the same objective.
In short, the ODR states that:
Some violations of the ODR must be diagnosed by the compiler. Other violations, particularly those that span translation units, are not required to be diagnosed.
In general, a translation unit shall contain no more than one definition of any class type. In this example, two definitions of the class type MyClass occur in the same translation unit. This typically occurs if a header file is included twice by the same source file without appropriate header guards.
class MyClass {}; // first definition of MyClass
class MyClass {}; // error, second definition of MyClass
In the following, forming a pointer to MyStruct or defining a function taking a reference to MyStruct are examples of legal constructs, because they do not require the type of MyStruct to be complete. Therefore, a definition is not required.
Defining an object of type MyStruct, a function taking an argument of type MyStruct, or using MyStruct in a sizeof expression are examples of contexts where S must be complete, and therefore require a definition.
struct MyStruct; // declaration of MyStruct
MyStruct* p; // ok, no definition required
void f(MyStruct&); // ok, no definition required
void f(MyStruct*); // ok, no definition required
MyStruct f(); // ok, no definition required - this is a function declaration only!
MyStruct s; // error, definition required
sizeof(MyStruct); // error, definition required
In certain cases, there can be more than one definition of a type or a template. A program consisting of multiple header files and source files will typically have more than one definition of a type, but not more than one definition per translation unit.
If a program contains more than one definition of a type, then each definition must be equivalent.
In pre-standard C++, all static data members required a definition outside of their class. However, during the C++ standardization process it was decided to lift this requirement for static const integral members. The intent was to allow uses such as:
struct MyClass {
static const int N = 10;
};
char data[MyClass::N]; // N "used" without out-of-class definition
without a namespace scope definition for N.
Nevertheless, the wording of the 1998 C++ standard still required a definition if the member was used in the program. This included the member appearing anywhere except as the operand to sizeof or typeid, effectively making the above ill-formed.
This was identified as a defect, and the wording was adjusted to allow such a member to appear anywhere a constant expression is required, without requiring an out-of-class definition. This includes array bounds, case expressions, static member initializers, and nontype template arguments.
struct MyClass1 {
static const int N = 10;
static const int U = N; // Legal per C++03
};
char data[Class1::N]; // Legal per C++03
template <int>
struct MyClass2;
template <>
struct MyClass2<Class1::N> {}; // Legal per C++03
However, using a static const integral member anywhere except where an integral constant-expression is required, requires a definition:
struct MyClass {
static const int N = 10;
};
int main() {
int i = MyClass::N; // Ill-formed in C++03. Definition of MyClass::N required.
}
This requirement was relaxed in a later standard, C++11.
We need 4 files: "Base.cppm", "Dummy1.cppm", "Dummy2.cppm", "Main.cpp".
Base.cppm:
module;
export module wikipedia.examples.Base;
export namespace wikipedia::examples {
// abstract base class
class Base {
public:
virtual void myFunc() = 0;
virtual ~Base() = default;
};
}
Dummy1.cppm
module;
export module wikipedia.examples.Dummy2;
import std;
import wikipedia.examples.Base;
export namespace wikipedia::examples {
class Dummy : public Base {
public:
void myFunc() override {
std::println("odr ONE dummy: Hello");
}
};
Base* odr1Create() {
return new Dummy();
}
}
Dummy2.cppm:
module;
export module wikipedia.examples.Dummy2;
import std;
import wikipedia.examples.Base;
export wikipedia::examples {
class Dummy : public Base {
public:
void myFunc() override {
std::println("odr TWO dummy: World");
}
};
Base* odr2Create() {
return new Dummy();
}
}
Main.cpp:
import wikipedia.examples.Base;
import wikipedia.examples.Dummy1;
import wikipedia.examples.Dummy2;
using wikipedia::examples::Base;
using wikipedia::examples::Dummy1;
using wikipedia::examples::Dummy2;
int main(int argc, char* argv[]) {
Base* o1 = odr1Create();
Base* o2 = odr2Create();
o1->myFunc();
o2->myFunc();
delete o1;
delete o2;
}
When executed the expected output is:
odr ONE dummy: Hello odr TWO dummy: World
But the likely output is:
odr ONE dummy: Hello odr ONE dummy: Hello
The problem is, that the C++ linker has to figure out how to build the virtual method table for the (two different) Dummy classes, and that only works if the class names are different.