我试图让编译器对某些我认为不违反C ++中一定义规则的代码作出反应。在头文件中,我有两个声明:一个声明用于结构,一个声明,如下所示:
struct TestStruct {
int a;
double d;
};
int k();
然后我故意将头文件两次放入另一个包含main()的文件中,以查看会发生什么。
令我惊讶的是,编译器抱怨该结构的多个定义。我希望编译器根本不会出现任何多重性错误,因为struct和function都具有纯声明。
只有在将结构放入标头保护程序之后,编译器才停止抱怨。但是,没有为该结构分配内存。这不是一个定义。那为什么编译器会发疯呢?
答案 0 :(得分:1)
在一个翻译单元中最多只能定义一个结构 。
您可以用几种翻译单位进行定义,但是定义必须相同。 (来源:cppreference/ODR)。
为避免此问题,您需要在标头中包含一个包含保护。它将默默地防止在每个翻译单元中多次包含标头。
答案 1 :(得分:0)
只使用一次包含保护(或编译器可用)的编译指示。
#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();
};
请注意,要避免muldef,您还需要在内联中声明k(),以决定在标头中提供其定义(有时,当您需要使用模板而不指定显式模板参数时,这是不可避免的)。 / p>
#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;