为什么结构声明违反了C++;? 我试图让编译器对我相信不违反C++中的一个定义规则的代码作出反应。在头文件中,我有两个声明:一个用于结构,一个用于函数,如下所示: struct TestStruct { int a; double d; }; int k();
然后我故意在另一个包含main()的文件中包含头文件两次,以查看会发生什么 令我惊讶的是,编译器抱怨结构有多个定义。我希望编译器根本不会引发任何多重性错误,因为结构和函数都有纯声明为什么结构声明违反了C++;? 我试图让编译器对我相信不违反C++中的一个定义规则的代码作出反应。在头文件中,我有两个声明:一个用于结构,一个用于函数,如下所示: struct TestStruct { int a; double d; }; int k();,c++,c++11,header-files,one-definition-rule,C++,C++11,Header Files,One Definition Rule,然后我故意在另一个包含main()的文件中包含头文件两次,以查看会发生什么 令我惊讶的是,编译器抱怨结构有多个定义。我希望编译器根本不会引发任何多重性错误,因为结构和函数都有纯声明 只有在我将结构放入头保护之后,编译器才会停止抱怨。但是,没有为结构分配内存。这不是一个定义。那么为什么编译器会疯狂呢?在一个翻译单元中不能多次定义一个结构 您可以在多个翻译单元中定义它,但定义必须相同。(来源:) 为了避免这个问题,你需要在你的标题中有一个include-guard。它将以静默方式防止在每个翻译单元中
只有在我将结构放入头保护之后,编译器才会停止抱怨。但是,没有为结构分配内存。这不是一个定义。那么为什么编译器会疯狂呢?在一个翻译单元中不能多次定义一个结构 您可以在多个翻译单元中定义它,但定义必须相同。(来源:) 为了避免这个问题,你需要在你的标题中有一个include-guard。它将以静默方式防止在每个翻译单元中多次包含标题。使用include-guard(或如果编译器提供)pragma一次
#ifndef PATH_TO_FILE_FILENAME_H
#define PATH_TO_FILE_FILENAME_H
struct TestStruct {
int a;
double d;
};
int k();
#endif
或者(如果有的话更好!)
也可能值得使用名称空间来避免污染全局名称空间
#pragma once
namespace Test
{
struct TestStruct {
int a;
double d;
};
int k();
};
请注意,为了避免muldef,如果决定在标头中提供其定义,还需要将k()声明为inline(如果需要使用模板而不指定显式模板参数,有时这是不可避免的)
在本例中,我们没有实现函数的基本内容,只是说它存在,而且由于编译器知道签名(或函数承诺获取和返回的内容),因此它可以愉快地继续。在TestStructs情况下,转发声明(不带实现)将是
class TestStruct;
这是一个结构定义。结构声明应该是
struct TestStruct是的,Etienne,我忘了声明应该是struct TestStruct;知道了。现在,这是有道理的。我认为结构声明实际上是一个定义。@Etienedemartel你应该给它一个答案!你好,猫,你能解释一下为什么定义必须相同吗?我们不是要避免“相同”的定义吗?链接器会抱怨。@softwarelover链接器不处理数据类型,只处理全局/静态变量和函数。@softwarelover(非内联)函数定义就是这样。但是,能够在不同的TU中对结构和类进行多个定义是很重要的:例如,当您在多个TU中#include
时,您可以在每个TU中有效地获得名称空间std{class string{…};}
。但是你没有得到链接器错误。@softwarelover是的,我肯定。您得到了std::string
(即class string{…};
而不是class string;
)的定义(实际上它是一个名为basic\u string
的模板,但我们忽略它)。如果类仅在TU中声明但未定义,则不能在该TU中创建它的对象(例如,class a;aa;
不编译)。@softwareloverclass a;A A无论您是否有类A{…},代码>都不会编译代码>是否在其他TU中(包括是否在链接库中)。“链接器自动链接标准库”是的,但这对类没有帮助。它允许您使用在标准头中声明(但未定义)的函数(包括成员函数)。但为了能够创建类的对象,其定义必须在同一TU中(但不一定是其成员函数的定义)。
#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.
class TestStruct;