我有一个概念上的疑问,我将尝试用一个例子来说明:
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
同样,如果你不使用这个函数,或者编译器内联了所有的出现,它可能会被优化掉。