基本 ODR 违规:.h 文件中的成员函数

Basic ODR violation: member functions in .h files

免责声明:这可能是一个基本问题,但我是一名理论物理学家,通过培训尝试学习正确编码,所以请耐心等待。

假设我想为一个相当复杂的物理系统建模。以我的理解,对该系统建模的一种方法是将其作为 class 引入。但是,由于涉及系统,class会很大,可能有很多数据成员、成员函数和subclasses。将主程序和这个 class 放在一个文件中会非常混乱,因此为了更好地了解项目,我倾向于将 class 放在一个单独的 .h 文件中。这样我就会有类似的东西:

//main.cpp

#include "tmp.h"

int main()
{
    myclass aclass;

    aclass.myfunction();

    return 0;
}

// tmp.h

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

    public: 

    // function members
    double myfunction();
};

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

然而,这相当于我的新编译器中的以下编译器警告:function definitions in header files can lead to ODR violations。那么我的问题是:处理这种情况的首选方法是什么?我想我可以将 tmp.h 变成 tmp.cpp,但据我所知,这是 .h 文件的预期用途吗?

通常,class 定义放在“.h”文件中,其成员函数的定义放在“.cpp”文件中。

如果你想在头文件中定义成员函数,你需要声明它们inline,或者将它们写在class定义中(这使得它们隐式内联)。

ODR 代表 One Definition Rule。这意味着一切都应该有一个且只有一个定义。现在,如果您在头文件中定义一个函数,则包含该头文件的每个翻译单元都将获得一个定义。这显然违反了 ODR。这就是编译器警告的内容。您有两种解决方法:

  1. 将函数声明移至 cpp 文件。这样就有一个定义。
  2. 创建函数inline。这意味着此函数可能有多个定义,但您确定所有定义都是相同的,并且链接器可能会使用其中一个而忽略其余部分。
  3. 创建函数static(不适用于class-方法)。当一个函数是 static 时,每个翻译单元都会得到它自己的方法副本,但它们都是不同的函数并且属于一个且仅属于一个编译单元。所以没关系。

添加到其他答案:

这是函数定义:

double myfunction()
{
    return foo + bar;
}

这是一个函数声明:

double myfunction();

声明的目的是声明函数对其他代码的唯一签名。该函数可以多次声明,但只能有一个定义,因此 ODR(单一定义规则)。

作为开始的基本规则,将函数声明放在 header 文件中,并将定义放在源文件中。

不幸的是,在 C++ 中,事情会迅速变得复杂。

只有函数签名可用的问题是您无法轻松优化函数中的代码,因为您看不到它。为了解决这个问题,C++ 允许在某些情况下将函数定义放在 header 中。

您必须使用 inline 关键字或将 myclass 的定义放入 .cpp 文件中。

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;
}

或者您可以使用 inline.

在 header (myclass.hpp) 中定义函数
#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

如果在 class 声明中定义 myFunction 函数,则可以省略 inline 关键字的使用。

#ifndef MY_CLASS_H
#define MY_CLASS_H

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

#endif