【问题标题】:Compilation error while including cpp file in main: Inline versus non-inline functions在 main 中包含 cpp 文件时出现编译错误:内联函数与非内联函数
【发布时间】:2014-06-24 10:35:38
【问题描述】:

我有一个概念上的疑问,我会尝试用一个例子来表达:

main.cpp

#include "array_list.cpp"
int main() 
{
  array_list list1;
  return 0;
}

场景 1: array_list.cpp->

class array_list
{
    private:
    int list[10];
public:
    array_list () {};
    ~array_list () {};
    void set_element (int,int);

};

void array_list::set_element (int i,int a) {
list[i] = a;
}

错误:

main.obj : error LNK2005: "public: void __thiscall array_list::set_element(int,int)" (?set_element@array_list@@QAEXHH@Z) 已在 array_list.obj 中定义 1>C:\Users\vrastog\Documents\Visual Studio 2012\Projects\C++ learning\Debug\list using arrays.exe:致命错误 LNK1169:找到一个或多个多重定义符号

场景 2: array_list.cpp->

class array_list
{
private:
    int list[10];
public:
    array_list () {};
    ~array_list () {};
    void set_element (int i,int a) {
        list[i] = a;
    }
};

错误:没有错误!!

问题:我了解错误的原因。相同的方法已经定义了两次,一次在 main.obj 中,第二次在 array_list.obj 中,因此,它应该是一个错误。 我的问题是为什么第二种情况有效?在这里,由于我们在主文件中包含了 array_list.cpp,所以这里也应该定义了两次“set_element”。我在这里错过了什么?

【问题讨论】:

  • 你到底为什么要包含.cpp 文件?!?这些不打算包含在内,而是单独编译并最终链接。
  • 我知道它不应该被包含在一个好的编码实践中。但理论上是可以的。我想通过这个例子了解底层的编译问题。
  • Including .cpp files的可能重复
  • 这个问题本质上是在问为什么一个内联函数可以被定义多次。
  • @Drew:没错!!

标签: c++ compilation linker inline redefinition


【解决方案1】:

请不要包含.cpp 文件。

第一个例子中,函数是类外定义的,需要加inline,否则是多重定义。

在第二个例子中,函数是在类定义中定义的,所以它是一个隐式内联函数(就像编译器为你添加了inline),这就是它不会导致多个定义的原因。

【讨论】:

    【解决方案2】:

    类内定义使方法内联,因此不会导致目标文件中的多重定义错误。


    inline 方法应在使用它的每个翻译单元中实现,因此inline 方法编译成两个 目标文件。

    C++ 标准草案 (n3797) 3.2.4:应在使用 odr 的每个翻译单元中定义内联函数。

    另外3.2.6要求这些功能要完全相同。

    g++ 使用弱符号实现这一点:内联函数是特殊的导出函数,在链接时不会导致多重定义错误。

    在 Linux 下使用nm 之类的工具,自己看看。它在目标文件中发出一个弱符号:

    $ nm arraylist.o
    00000000 W _ZN10array_list11set_elementEii
    (... ctors, dtors ...)
    00000000 T main
    

    另外,如果你不使用这个函数,或者编译器内联所有出现的地方,它可能会被优化出来。

    【讨论】:

    • 你的意思是它不在 main.obj 或 array_list.obj 或两者中?如果它没有进入任何 obj 文件,那么内联方法在哪里编译?
    • @user267096 我已扩展(并更正)答案以包含您问题的答案。
    • 感谢您的回答。主要解决了我的疑问。作为一个扩展,内联函数应该在每个必须使用它的翻译单元中都有定义的原因可能是什么?
    • @tyl3rdurd3n 如果您看到函数的定义,您可以进行内联。如果在翻译单元中看不到函数的定义,编译器所能做的就是生成一个函数调用。
    猜你喜欢
    • 2011-05-12
    • 1970-01-01
    • 2012-01-17
    • 2011-04-28
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 2016-03-10
    • 2014-02-13
    相关资源
    最近更新 更多