在main中包含cpp文件时的编译错误:内联函数与非内联函数

Compilation error while including cpp file in main: Inline versus non-inline functions

本文关键字:函数 错误 编译 main 包含 cpp 文件      更新时间:2023-10-16

我有一个概念上的疑问,我将尝试用一个例子来说明:

main.cpp

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

Scenario1: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;
}
错误:

主要。objecj:错误LNK2005: "public: void __thiscall array_list::set_element(int,int)"(?set_element@array_list@@QAEXHH@Z)已经在array_list.obj中定义1>C:UsersvrastogDocumentsVisual Studio 2012Projects c++ learningDebuglist 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;
    }
};

Error: No Error !!

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

请不要包含.cpp文件。

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

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

类内定义使方法内联,因此它不会在对象文件中导致多重定义错误。


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

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

3.2.6要求这两个函数应该完全相同。

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

在Linux下使用nm这样的工具自己看看。它在对象文件中发出一个弱符号:

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

同样,如果你不使用这个函数,或者编译器内联了所有的出现,它可能会被优化掉。