为什么跨cpp文件定义类不会导致链接器错误?

rcp*_*lus 7 c++ linker class c++11

如果我有一个foo.cpp包含以下代码的文件:

class Foo {
};

class Foo {
};

int main() {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后我自然而然error: redefinition of 'Foo'.但是,如果我有foo.cpp

class Foo {
};

int main() {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

bar.cpp

class Foo {
};
Run Code Online (Sandbox Code Playgroud)

尽管class Foo在整个程序中被定义了两次,但整个事情编译得很好.

如果我int something;在全局命名空间中放入了两个文件,那么我会得到一个链接器错误(特别是duplicate symbol),但是对于类定义,这种情况永远不会发生.

我知道函数声明,例如int doIt();可以在两个cpp文件中复制,但是一个定义,例如int doIt() {} 不能.现在,在第一个编译器错误(class Foo{};在一个cpp文件中有两次),它说redefinition of foo,class Foo{};定义也是如此.那么为什么,与功能不同,它可以在一个程序中定义两次?

编辑:根据这个网站,命名类有外部链接.那么为什么class Foo两个cpp文件之间没有冲突呢?

EDIT2:根据上面链接的网站,命名类不仅具有外部链接,而且它也是静态成员.但这一切都很好:

foo.cpp:

class Foo {
public:
    int foo();
    static int x;
};

int Foo::foo() {
    return 5;
}

int main() {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

bar.cpp:

class Foo {
public:
    int foo(int);
    static bool x;
};

int Foo::foo(int i) {
    return i * 2;
}
Run Code Online (Sandbox Code Playgroud)

不仅Foo::foo使用不同的签名重新定义,而且Foo::x具有不同的类型.这两个都应该有外部链接,但这个代码是A-ok.

Joh*_*ith 3

关于你的第一个问题,多个 TU 具有相同的定义,这是 ODR 明确允许的,因为否则该语言将毫无用处。

关于第二个问题,不同的 TU 有不同的定义,这违反了 ODR。然而,这些都是 NDR。你的程序仍然是畸形的,并且可能会导致奇怪的错误。

关于第三个问题,对于static数据成员来说,那些是声明,而不是定义。他们需要一个独特的定义,例如:

TheType ClassName::VariableName;
Run Code Online (Sandbox Code Playgroud)

这些通常放置在随附的 .cpp 文件中。

有一个例外,即const static具有内联初始值设定项的数据成员。


ODR = 一种定义规则
TU = 翻译单元
NDR = 无需诊断

关于 NDR 的说明;编译器很难检测到某些类型的错误,并且标准通常不要求编译器在这些情况下发出诊断(即警告或错误)。有些工具(例如 CppLint)可以检测到编译器无法检测到的许多错误。当涉及 ODR 违规时,通常可以通过仅在标头中定义类型来避免这些违规。