据我所知,一个类可以在多个翻译单元中定义,只要它们是相同的。考虑到这一点,请考虑以下示例:
//1.cpp
class Foo{
public:
int i;
};
void FooBar();
void BarFoo(){
Foo f;
}
int main(){
FooBar();
BarFoo();
}
//2.cpp
class Foo{
public:
std::string s;
};
void FooBar(){
Foo f;
}
这个编译,我不会崩溃。
如果我做了以下更改:
//1.cpp
Foo FooBar();
//2.cpp
Foo FooBar(){
Foo f;
return f;
}
我遇到了崩溃。为什么一个导致崩溃而另一个导致崩溃。另外,我在第一个例子中没有违反ODR吗?如果我是,为什么编译好?
答案 0 :(得分:1)
由于您声明的原因,该计划格式不正确。编译器不需要诊断程序,但我没有看到在一个不正确的程序中讨论崩溃的原因。
仍然,让我们这样做:
第一个示例可能不会崩溃,因为FooBar
的行为不会影响main
的运行。该方法被调用,它做了一些事情,就是这样。
在第二个示例中,您尝试返回Foo
。 FooBar
会返回Foo
中定义的2.cpp
版本。 main
中显示1.cpp
,因此它需要Foo
中定义的版本1.cpp
,这是一个完全不同的版本 - 不同的成员,大小。你最有可能在析构函数上腐败。 (只是一个猜测)
6)在程序中可以有多个类类型[...]的定义,只要每个定义都有 出现在不同的翻译单元中,并且定义满足以下要求。 [...]
- D的每个定义应由相同的令牌序列组成;
[...]
答案 1 :(得分:0)
以下是编译器/链接器的工作原理:
编译器转换具有提供的标头的cpp文件。它会生成一个.obj文件。在您的情况下,o.bj文件将引用data-struct Foo
。并且没有任何其他细节。
链接器将.obj文件链接在一起。它只比较字符串名称。在您的obj文件中,您拥有相同的Foo
。名字匹配。对于链接器,这是一回事。
之后你开始你的程序。最有可能它会崩溃。更具体地说,它将显示未定义的行为。它可以进入无限循环,显示奇怪的消息等。
您有责任在cpp文件中提供相同的标头或定义到每个cpp文件的翻译中。现有的软件工具无法为您检查。这是它的工作原理。