0

I am not able to understand that why this code gives linker error. I have a project with these two files

myclass.cpp

class MyClass
{
    public:
    void SomeFun(){ ... } // SomeFun is defined here
};

main.cpp

class MyClass
{
    public:
    void SomeFun(); // SomeFun is declared here
};

int main()
{
    MyClass obj;
    obj.SomeFun(); // This throws undefined reference linker error during build. Why?
}

1: In Summary, I have a class "MyClass" with function "SomeFun" declared in main.cpp and defined in myclass.cpp. I expected the build to succeed since during linking stage it should have found the definition of SomeFun(). But it fails !

2: But why does it work fine if I just move the class declaration in lets say file "myclass.h" and include that header in both cpp ( with function body defined in myclass.cpp). How header file is making difference?

Avi
  • 71
  • 5
  • You could use the exact same class definition in both files without header, but of course you should use headers instead. https://wandbox.org/permlink/qrhFMpIfrkWAwgia – jabaa Jul 22 '22 at 14:15
  • [Dupe1](https://stackoverflow.com/questions/9364720/c-different-classes-with-the-same-name-in-different-translation-units), [Dupe2](https://stackoverflow.com/questions/12868576/class-defined-in-different-translation-units) and [Dupe3](https://stackoverflow.com/questions/57516685/why-does-the-same-class-being-defined-in-multiple-cpp-files-not-cause-a-linker) – Jason Jul 22 '22 at 14:30
  • 1
    Undefined behaviour since the definitions of class `MyClass` differs between the two source files. According to the standard, two class definitions are only identical if their definitions include exactly the same set of tokens scanned by the compiler. Having one class definition with a member function declared (and not defined) and another definition of the same class with that member defined does actually mean their definition has a different set of tokens. When behaviour is undefined, a linker error is one possibility. – Peter Jul 22 '22 at 14:32
  • As others mentioned, it's undefined behavior,so anything can happen. However, the reason you see this particular symptom is probably related to [Why are class member functions inlined?](https://stackoverflow.com/questions/9734175/why-are-class-member-functions-inlined) – JaMiT Jul 22 '22 at 14:35

1 Answers1

3

This in myClass.cpp

class MyClass
{
    public:
    void SomeFun(){ ... } // SomeFun is defined here
};

Is a definition for MyClass. This in main.cpp

class MyClass
{
    public:
    void SomeFun(); // SomeFun is declared here
};

Is another definition of MyClass.

The one-definition-rule (ODR) states:

Only one definition of any variable, function, class type, enumeration type, concept (since C++20) or template is allowed in any one translation unit (some of these may have multiple declarations, but only one definition is allowed). ) [...]

Further...

There can be more than one definition in a program of each of the following: class type, enumeration type, inline function, inline variable (since C++17), templated entity (template or member of template, but not full template specialization), as long as all of the following is true:

  • each definition appears in a different translation unit
  • the definitions are not attached to a named module (since C++20)
  • each definition consists of the same sequence of tokens (typically, appears in the same header file)
  • [...]

If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the program is ill-formed, no diagnostic required.


1: [...] But it fails !

It fails because its an ODR violation. The two definitions do not consist of the same sequence of tokens.

2: But why does it work fine if I just move the class declaration in lets say file "myclass.h" and include that header in both cpp

Because then there is only a single definition in your program. Also including the same header in different translation units is fine, because then all definitions do consist of the same sequence of tokens.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • 1
    Or you could use the exact same class definition in both files (without header). Just for technical explanation of the problem. https://wandbox.org/permlink/qrhFMpIfrkWAwgia – jabaa Jul 22 '22 at 14:11
  • @jabaa the last sentence isnt meant to restrict the second last but rather to answer OPs 2. Could be more clear perhaps... – 463035818_is_not_an_ai Jul 22 '22 at 14:17
  • Your answer is completely correct, but I think the OP could better understand the problem regarding the different tokens with this example. It shows that you don't need a header, but identical definitions. – jabaa Jul 22 '22 at 14:23
  • Thanks people for clarification @jabaa I understand now ,how we can accomplish the same without header – Avi Jul 22 '22 at 14:34