【发布时间】:2019-07-25 21:10:29
【问题描述】:
让我们从以下一组 C++ 文件开始:
// my_class.h
struct MyClass
{
void my_func();
};
void MyClass::my_func()
{}
// f.h
void f1();
void f2();
// f1.cpp
#include "my_class.h"
void f1()
{
MyClass a;
a.my_func();
}
// f2.cpp
#include "my_class.h"
void f2()
{
MyClass a;
a.my_func();
}
// main.cpp
#include "f.h"
int main()
{
f1();
f2();
return 0;
}
我试图用
编译这段代码$ g++ f1.cpp f2.cpp main.cpp
显然,链接器抱怨重复符号my_func:
duplicate symbol __ZN7MyClass7my_funcEv in:
/var/folders/yj/zz96q16j6vd1dq1_r3mz8hzh0000gn/T/f1-962ae7.o
/var/folders/yj/zz96q16j6vd1dq1_r3mz8hzh0000gn/T/f2-aef78c.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我的下一个尝试是将函数定义移动到类定义中,所以我们得到:
struct MyClass
{
void my_func()
{}
};
运行同样的g++ 命令,程序编译成功。这是因为在类定义中定义的函数被隐式标记为 inline (§10.1.6 * 3)。
标准规定:
带有 inline 说明符的函数声明(11.3.5、12.2.1、14.3)声明了一个内联函数。 inline 说明符向实现表明,在调用点对函数体进行内联替换优于通常的函数调用机制。在调用点执行此内联替换不需要实现;但是,即使省略了此内联替换,本节中指定的内联函数的其他规则仍应遵守
这似乎与cppreference.com 上的内容有些矛盾:
因为函数的关键字 inline 的含义是“允许多个定义”而不是“首选内联”,[...]
据我所知,在类定义中定义一个函数会隐含inline,这并不一定意味着编译器会选择内联它的主体,而是会在每个翻译单元中定义它。这是正确的吗?
第二个问题是关于模板类的。分离模板类的声明/定义是一个问题,正如here 所述,所以我们只能在类定义中包含函数定义,这使得它隐含inline,对吧?这有什么影响?
既然类是模板时我们只能选择在类定义中定义函数,那么对于非模板类该怎么办呢?我们应该在源文件中定义函数,并且尽可能只在头文件中保留声明吗?
【问题讨论】:
-
问题是在你的情况下
my_func没有在类定义中定义。它只在那里声明。 -
@NO_NAME 第二个例子正好说明了这一点:在类定义中包含函数定义
-
“因为当类是模板时,我们只能选择在类定义中定义函数”这是不正确的,所以剩下的问题是无用的
-
“第二题来了”,请一题一题
-
@Victor 是的,不要想太多包括警卫。它们很有用,但在这个问题的上下文中毫无意义。
标签: c++