2

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?

storluffarn
  • 121
  • 2
  • 11
  • 1
    Either put `inline` in front of `double myclass::myfunction()` or put the definition in tmp.cpp – Jarod42 Mar 08 '21 at 11:15
  • 1
    To my surprise, there seems to be no obvious duplicate, although there are similar questions about non-member functions. However, the rules for member functions are slightly different, so those other Q's are not duplicates. – MSalters Mar 08 '21 at 11:21

4 Answers4

8

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).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
3

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
QuatCoder
  • 232
  • 1
  • 5
2

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
WBuck
  • 5,162
  • 2
  • 25
  • 36
0

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.
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • "Now, if you define a function in a header file, every translation unit that includes that header file will get a definition." Yeah, that's a yikes, I had no idea, but okay, `inline` is your friend, or just keep functions in .cpp files! Thanks for clearing the meaning of ODR up! – storluffarn Mar 08 '21 at 12:44
  • 1
    @storluffarn if you know what `#include` does, the ODR violation is not surprising at all. I also don't recommend you go around sprinkling `inline` everywhere. In general, you `inline` very short methods and move everything else to a cpp file. – Aykhan Hagverdili Mar 08 '21 at 12:47
  • Sure, as per other suggestions here I will start separating class definitions and declarations into separate files, that ought to do it. I.e. have the .h file with declarations of classes and functions, and then .cpp files with their actual definitions. – storluffarn Mar 08 '21 at 13:44