简体   繁体   English

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

[英]Basic ODR violation: member functions in .h files

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.假设我想要 model 一个相当复杂的物理系统。 In my understanding, one way of modelling this system is to introduce it as a class.据我了解,对该系统进行建模的一种方法是将其引入为 class。 However, since the system involved, the class will be large, with potentially many data members, member functions and subclasses.但是,由于涉及系统,class 将很大,可能包含许多数据成员、成员函数和子类。 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.将主程序和 class 放在一个文件中会非常混乱,因此为了更好地了解项目,我倾向于将 class 放在单独的.h 文件中。 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 .但是,这相当于我的新编译器中的以下编译器警告: 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?我想我可以将 tmp.h 变成 tmp.cpp,但据我所知,这是 .h 文件的预期用途吗?

Normally, a class definition goes in an ".h" file and its member functions' definitions go in a ".cpp" file.通常,class 定义位于“.h”文件中,其成员函数的定义 go 位于“.cpp”文件中。

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).如果要在 header 中定义成员函数,则需要将它们声明为inline ,或者将它们写入 class 定义中(这使它们隐式内联)。

Adding to the other answers:添加到其他答案:

This is a function definition :这是 function定义

double myfunction()
{
    return foo + bar;
}

This is a function declaration :这是 function声明

double myfunction();

The purpose of the declaration is to declare the unique signature of the function to other code.声明的目的是将 function 的唯一签名声明给其他代码。 The function can be declared many times, but can only have one definition, hence the ODR (One Definition Rule). function 可以多次声明,但只能有一个定义,因此是 ODR(One Definition Rule)。

As a basic rule to start with, put function declarations in header files, and put definitions in source files.作为开始的基本规则,将 function 声明放在 header 文件中,并将定义放在源文件中。

Unfortunately in C++, things rapidly get more complicated.不幸的是,在 C++ 中,事情很快变得更加复杂。

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.仅使用 function 签名的问题在于,您无法轻松优化 function 中的代码,因为您看不到它。 To solve that problem, C++ allows function definitions to be put in headers in several circumstances.为了解决这个问题,C++ 允许在几种情况下将 function 定义放在标题中。

You'll have to either use the inline keyword or put the definition of myclass in a .cpp file.您必须使用inline关键字或将myclass的定义放在.cpp文件中。

myclass.hpp我的类.hpp

#ifndef MY_CLASS_H
#define MY_CLASS_H

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

#endif

myclass.cpp我的类.cpp

#include "myclass.hpp"

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

Or you can define the function in the header ( myclass.hpp ) using inline .或者您可以使用inline在 header ( myclass.hpp ) 中定义 function 。

#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.如果您在class声明中定义myFunction function,则可以省略inline关键字的使用。

#ifndef MY_CLASS_H
#define MY_CLASS_H

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

#endif

ODR stands for One Definition Rule . ODR 代表一个定义规则 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.现在,如果您在 header 文件中定义 function ,则包含该 header 文件的每个翻译单元都将获得一个定义。 That obviously violates the ODR.这显然违反了 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.将 function 声明移动到cpp文件。 That way there is a single definition.这样就有了一个单一的定义。
  2. Make the function inline .使 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.这意味着这个 function 可能有多个定义,但您确定所有定义都是相同的,并且 linker 可能使用其中一个而忽略 rest。
  3. Make the function static (doesn't apply to class-methods).制作 function static (不适用于类方法)。 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.当 function 为static时,每个翻译单元都有自己的方法副本,但它们都是不同的功能,属于一个且仅属于一个编译单元。 So it's OK.所以没关系。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM