Basic ODR violation: member functions in .h files

7.7k views Asked by At

Disclaimer: This is probably a basic question, but I'm a theoretical physicist by training trying to learn to code properly, so please bear with me.

Let's say that I want to model a fairly involved physical system. In my understanding, one way of modelling this system is to introduce it as a class. However, since the system involved, the class will be large, with potentially many data members, member functions and subclasses. Having the main program and this class in one file will be very cluttered, so to give a better overview of the project I tend to put the class in a separate .h file. Such that I'd have something like:

//main.cpp

#include "tmp.h"

int main()
{
    myclass aclass;

    aclass.myfunction();

    return 0;
}

and

// tmp.h

class myclass
{
    // data members
    double foo;
    double bar;

    public: 

    // function members
    double myfunction();
};

double myclass::myfunction()
{
    return foo + bar;
}

This however, amounts to the following compiler warning in my new compiler: function definitions in header files can lead to ODR violations. My question then is this: what is actually the preferred way of dealing with a situation like this? I guess I can just make tmp.h into tmp.cpp, but to the best of my understanding, this is the intended use of .h files?

4

There are 4 answers

5
molbdnilo On BEST ANSWER

Normally, a class definition goes in an ".h" file and its member functions' definitions go in a ".cpp" file.

If you want to define member functions in the header, you need to either declare them inline, or write them inside the class definition (which makes them implicitly inline).

3
Aykhan Hagverdili On

ODR stands for One Definition Rule. It means that everything should have one and only one definition. Now, if you define a function in a header file, every translation unit that includes that header file will get a definition. That obviously violates the ODR. That's what the compiler is warning about. You have couple of ways to work around that:

  1. Move the function declaration to a cpp file. That way there is a single definition.
  2. Make the function inline. This means that there may be multiple definitions of this function, but you're sure that all are identical and the linker may use one those and ignore the rest.
  3. Make the function static (doesn't apply to class-methods). When a function is static each translation unit gets it's own copy of the method, but they are all different functions and belong to one and only one compilation unit. So it's OK.
1
QuatCoder On

Adding to the other answers:

This is a function definition:

double myfunction()
{
    return foo + bar;
}

This is a function declaration:

double myfunction();

The purpose of the declaration is to declare the unique signature of the function to other code. The function can be declared many times, but can only have one definition, hence the ODR (One Definition Rule).

As a basic rule to start with, put function declarations in header files, and put definitions in source files.

Unfortunately in C++, things rapidly get more complicated.

The problem with just having the function signature available is that you can't easily optimise the code in the function, because you can't see it. To solve that problem, C++ allows function definitions to be put in headers in several circumstances.

0
WBuck On

You'll have to either use the inline keyword or put the definition of myclass in a .cpp file.

myclass.hpp

#ifndef MY_CLASS_H
#define MY_CLASS_H

class myclass
{
public:
    double myfunction( );
private: 
    double foo;
    double bar;
};

#endif

myclass.cpp

#include "myclass.hpp"

double myclass::myFunction( ) 
{
    return foo + bar;
}

Or you can define the function in the header (myclass.hpp) using inline.

#ifndef MY_CLASS_H
#define MY_CLASS_H

class myclass
{
public:
    double myfunction( );
private: 
    double foo;
    double bar;
};

inline double myclass::myFunction( ) 
{
    return bar + foo;
}
#endif

If you define the myFunction function in the class declaration then you can omit the use of the inline keyword.

#ifndef MY_CLASS_H
#define MY_CLASS_H

class myclass
{
public:
    double myfunction( )
    {
        return foo + bar;
    }
private: 
    double foo;
    double bar;
};

#endif