我这里有一些简单的代码:
// main.cpp
#include <iostream>
#include "foo.h"
int main() {
Foo foo;
foo.spam();
std::cout << "In main: sizeof (Foo) = " << sizeof (Foo) << std::endl;
return 0;
}
// foo.h
#ifndef FOO_H
#define FOO_H
class Foo {
public:
int bar;
void spam();
};
#endif
// foo.cpp
#include <iostream>
#include "foo.h"
void Foo::spam() {
std::cout << "sizeof (Foo) = " << sizeof (Foo) << std::endl;
}
程序很简单,我们很容易预见输出:
sizeof (Foo) = 4
In main: sizeof (Foo) = 4
但是对于include指令,预处理器只是用包含的文件内容替换它们,因此foo
的声明同时出现在main.cpp
和foo.cpp
中。 如果我们手动将foo
的声明放在main.cpp
中,并像这样故意修改它,会怎么样?
// main.cpp
#include <iostream>
// #include "foo.h" replaced with declaration of foo
#ifndef FOO_H
#define FOO_H
class Foo {
public:
int bar, baz, qux, eggs; // added some members
void spam();
};
#endif
int main() {
Foo foo{111, 222, 333, 444};
foo.spam();
std::cout << "In main: sizeof (Foo) = " << sizeof (Foo) << std::endl;
std::cout << "foo.qux = " << foo.qux << std::endl; // try to access the newly added qux member
return 0;
}
现在main.cpp
和foo.cpp
中的foo
的两个声明是不同的,但是程序仍然编译并运行! 输出变成
sizeof (Foo) = 4
In main: sizeof (Foo) = 16
foo.qux = 333
这里到底发生了什么?! 为什么foo
可以在一个程序中有两个不同的声明? 为什么还要编译这个?
class Foo;
是一个声明,但是
class Foo {};
是一个定义。
因此,您的程序中有多个foo
的定义。 这违反了“一个定义规则”,该规则规定程序中的每个实体必须有一个定义。
违反ODR会导致未定义的行为,因此对程序的输出进行推理是没有意义的。
您的代码具有未定义的行为。 在C++中,有一个规则叫做一个定义规则。 从根本上说,一个事物只能有一个定义,任何违反这一定义的行为都是不正确的--不需要诊断。
由于您有两个foo
的定义,当您将一个添加到main.cpp
时,您就违反了这一定义,并且您得到的任何结果都是“正确的”。