0

I was wondering about declarations and definitions of class methods in different translational units. I know that this is not the way to do things at all, but I think it serves as good examples for understanding about linking and compilation, so please, bear with me. =)

So I have two files: extra.cpp and main.cpp, both have a an explicit and different forward declaration of class A. Clearly, the One Definition Rule is violated, yet it compiles and links without any complains. My question is shown in the output in the main file, and, why is it actually compiling?

extra.cpp

#include <iostream>

class A{
public:
void method1(){std::cout << "method 1 defined in class declaration in extra.cpp" << '\n';}
void method2();
};

void A::method2(){std::cout << "method 2 defined out of declaration in extra.cpp" << '\n';}

main.cpp

#include <iostream>

class A{
public:
void method1();
void method2(){std::cout << "method 2 defined in class declaration in main.cpp" << '\n';};
};

void A::method1(){std::cout << "method 1 defined out of class declaration in main.cpp" << '\n';}

int main(int argc, char const *argv[]) {
  A a;
  a.method1();
  a.method2();
  return 0;
}

/* OUTPUT

method 1 defined out of declaration in main.cpp //  Ok, its defined and declared in the same translation unit,
 this makes sense

method 2 defined out of declaration in extra.cpp // Why is it taking the definition on a different translation unit,
 and ignoring the one in the header.
*/
learning_dude
  • 1,030
  • 1
  • 5
  • 10
  • 1
    both translation units will compile as you expect but the linker will see two definitions of class `A` and simply discard one of them and keep the other. Your code violates the One Definition Rule and therefore has undefined behaviour – Alan Birtles May 02 '21 at 19:34
  • 2
    With the ODR violation, the linker will typically pick one of the definitions and ignore the rest. You may get different results with full optimization (where the call to `a.method2()` is inlined) vs no optimization (where it is not). – 1201ProgramAlarm May 02 '21 at 19:34
  • Nitpick, but neither file has a _forward_ declaration of `A`. They both have definitions of `A`, but some of the member method declarations are not immediately defined. A forward declaration would be just `class A;` without declaring member variables (in this case, `A` has none) and member functions. – Nathan Pierson May 02 '21 at 19:36
  • I'm surprised the linker did not complain; usually there's an error if the same symbol is defined in multiple object files. If you want to introduce a type that is only used in the same file, imho it should go into a unnamed namespace to prevent any name conflicts. – fabian May 02 '21 at 19:37
  • This is ODR violation. But it kind of works because `A::method1` of `extra.cpp` and `A::method2` in `main.cpp` are defined inside the class, so they are implicitly declared `inline`! And `inline` by design allow ODR violation in this sense that the linker will pick one, _assuming all definitions are the same_, which is false here. – prapin May 02 '21 at 20:11
  • @AlanBirtles Why is it compiling, then? – learning_dude May 02 '21 at 20:26
  • @1201ProgramAlarm With ODR violation it should not compile. Why is it compiling then? – learning_dude May 02 '21 at 20:26
  • 1
    The linker sees normal symbols of the two out-of-line definitions, and weak symbols for the inline versions. Since normal symbols are available, the linker throws away the weak symbols, and no duplicate definitions occur. – j6t May 02 '21 at 20:29
  • 2
    @learning_dude -- "With ODR violation it should not compile." -- no, that's not the case. An ODR violation results in undefined behavior. The compiler is not required to diagnose it. – Pete Becker May 02 '21 at 20:34

0 Answers0