我试图让编译器对一些我认为不违反C++中一个定义规则的代码做出反应。在头文件中,我有两个声明:一个用于结构,一个用于函数,如下所示:
struct TestStruct {
int a;
double d;
};
int k();
然后我故意在另一个带有main((的文件中包含两次头文件,看看会发生什么。
令我惊讶的是,编译器抱怨结构的多个定义。我希望编译器根本不会引发任何多重性错误,因为结构和函数都有纯声明。
只有在我将结构放入标头保护中后,编译器才会停止抱怨。但是,没有为结构分配内存。它不是一个定义。那编译器为什么会生气呢?
不能在单个翻译单元中多次定义结构。
您可以在多个翻译单元中定义它,但定义必须相同。(资料来源:cpp偏好/ODR(。
若要避免此问题,需要在标头中设置包含保护。它将静默地防止标头在每个翻译单元中多次包含。
使用包含保护(或者如果您的编译器可用(编译指示一次。
#ifndef PATH_TO_FILE_FILENAME_H
#define PATH_TO_FILE_FILENAME_H
struct TestStruct {
int a;
double d;
};
int k();
#endif
或者(如果有的话,那就更好了!
#pragma once
struct TestStruct {
int a;
double d;
};
int k();
也可能值得使用命名空间以避免污染全局命名空间
#pragma once
namespace Test
{
struct TestStruct {
int a;
double d;
};
int k();
};
请注意,为了避免 muldefs,如果您决定在标头中提供其定义,您还需要内联声明 k(((如果您需要使用模板而不指定显式模板参数,这有时是不可避免的(。
#pragma once
namespace Test
{
struct TestStruct {
int a;
double d;
};
template<typename T>
inline int k<T>() // This now has to be inline or static.
{
// Some implementation
}
};
编辑:顺便说一句,结构/类的声明和定义之间的区别与函数没有太大区别:
void TestFunction(); // The compiler now knows there's a function called TestFunctionand can attempt to link the symbol information to its implementation somewhere in the compilation unit.
在这种情况下,我们不是在实现函数的实质,只是说它存在,并且由于编译器知道签名(或函数承诺获取和返回的内容(,它可以愉快地继续。在 TestStructs 的情况下,前向声明(不带实现(将是
class TestStruct;