为什么结构声明违反了C++;? 我试图让编译器对我相信不违反C++中的一个定义规则的代码作出反应。在头文件中,我有两个声明:一个用于结构,一个用于函数,如下所示: struct TestStruct { int a; double d; }; int k();

为什么结构声明违反了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。它将以静默方式防止在每个翻译单元中

然后我故意在另一个包含main()的文件中包含头文件两次,以查看会发生什么

令我惊讶的是,编译器抱怨结构有多个定义。我希望编译器根本不会引发任何多重性错误,因为结构和函数都有纯声明


只有在我将结构放入头保护之后,编译器才会停止抱怨。但是,没有为结构分配内存。这不是一个定义。那么为什么编译器会疯狂呢?

在一个翻译单元中不能多次定义一个结构

您可以在多个翻译单元中定义它,但定义必须相同。(来源:)

为了避免这个问题,你需要在你的标题中有一个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#include
时,您可以在每个TU中有效地获得
名称空间std{class string{…};}
。但是你没有得到链接器错误。@softwarelover是的,我肯定。您得到了
std::string
(即
class string{…};
而不是
class string;
)的定义(实际上它是一个名为
basic\u string
的模板,但我们忽略它)。如果类仅在TU中声明但未定义,则不能在该TU中创建它的对象(例如,
class a;aa;
不编译)。@softwarelover
class 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;