在不同的翻译单元中定义的类

时间:2012-10-12 23:49:14

标签: c++

据我所知,一个类可以在多个翻译单元中定义,只要它们是相同的。考虑到这一点,请考虑以下示例:

 //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吗?如果我是,为什么编译好?

2 个答案:

答案 0 :(得分:1)

由于您声明的原因,该计划格式不正确。编译器不需要诊断程序,但我没有看到在一个不正确的程序中讨论崩溃的原因。

仍然,让我们这样做:

第一个示例可能不会崩溃,因为FooBar的行为不会影响main的运行。该方法被调用,它做了一些事情,就是这样。

在第二个示例中,您尝试返回FooFooBar会返回Foo中定义的2.cpp版本。 main中显示1.cpp,因此它需要Foo中定义的版本1.cpp,这是一个完全不同的版本 - 不同的成员,大小。你最有可能在析构函数上腐败。 (只是一个猜测)

编辑:这确实打破了一个定义规则:

3.2一个定义规则[basic.def.odr]

  

6)在程序中可以有多个类类型[...]的定义,只要每个定义都有   出现在不同的翻译单元中,并且定义满足以下要求。 [...]

     
      
  • D的每个定义应由相同的令牌序列组成;
  •   
     

[...]

答案 1 :(得分:0)

以下是编译器/链接器的工作原理:

  1. 编译器转换具有提供的标头的cpp文件。它会生成一个.obj文件。在您的情况下,o.bj文件将引用data-struct Foo。并且没有任何其他细节。

  2. 链接器将.obj文件链接在一起。它只比较字符串名称。在您的obj文件中,您拥有相同的Foo。名字匹配。对于链接器,这是一回事。

  3. 之后你开始你的程序。最有可能它会崩溃。更具体地说,它将显示未定义的行为。它可以进入无限循环,显示奇怪的消息等。

  4. 您有责任在cpp文件中提供相同的标头或定义到每个cpp文件的翻译中。现有的软件工具无法为您检查。这是它的工作原理。