C ++:在不同的翻译单元中具有相同名称的不同类 [英] C++: Different classes with the same name in different translation units

查看:102
本文介绍了C ++:在不同的翻译单元中具有相同名称的不同类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下示例:

// usedclass1.hpp  
#include <iostream>  
class UsedClass
{  
public:
  UsedClass() { }  
  void doit() { std::cout << "UsedClass 1 (" << this << ") doit hit" << std::endl; }
};  

// usedclass2.hpp  
#include <iostream>
class UsedClass
{
public:
  UsedClass() { }
  void doit() { std::cout << "UsedClass 2 (" << this << ") doit hit" << std::endl; }
};

// object.hpp
class Object
{
public:
  Object();
};

// object.cpp
#include "object.hpp"
#include "usedclass2.hpp"
Object::Object()
{
  UsedClass b;
  b.doit();
}

// main.cpp
#include "usedclass1.hpp"
#include "object.hpp"
int main()
{
  Object obj;
  UsedClass a;
  a.doit();
}

代码编译时没有任何编译器或链接器错误.但是输出对我来说很奇怪:

The code compiles without any compiler or linker errors. But the output is strange for me:

  • Fedora x86_64上的gcc(Red Hat 4.6.1-9),无优化[ EG1 ]:

UsedClass 1(0x7fff0be4a6ff)doit hit
UsedClass 1(0x7fff0be4a72e)doit hit

UsedClass 1 (0x7fff0be4a6ff) doit hit
UsedClass 1 (0x7fff0be4a72e) doit hit

  • 与[EG1]相同,但启用了-O2选项[ EG2 ]:

    UsedClass 2(0x7fffcef79fcf)doit hit
    UsedClass 1(0x7fffcef79fff)doit hit

    UsedClass 2 (0x7fffcef79fcf) doit hit
    UsedClass 1 (0x7fffcef79fff) doit hit

  • Windows XP 32位上的
  • msvc2005(14.00.50727.762),无优化[ EG3 ]:

  • msvc2005 (14.00.50727.762) on Windows XP 32bit with no optimization [EG3]:

    UsedClass 1(0012FF5B)doit hit
    UsedClass 1(0012FF67)doit hit

    UsedClass 1 (0012FF5B) doit hit
    UsedClass 1 (0012FF67) doit hit

  • 与[EG3]相同,但启用了/O2(或/Ox)[ EG4 ]:

    UsedClass 1(0012FF73)doit hit
    UsedClass 1(0012FF7F)doit hit

    UsedClass 1 (0012FF73) doit hit
    UsedClass 1 (0012FF7F) doit hit

  • 我期望链接器错误(假设违反了ODR规则)或输出如[EG2]中的内容(内联代码,未从翻译单元中导出任何内容,保留了ODR规则).因此,我的问题是:

    I would expect either a linker error (assuming ODR rule is violated) or the output as in [EG2] (code is inlined, nothing is exported from the translation unit, ODR rule is held). Thus my questions:

    1. 为什么可以输出[EG1],[EG3],[EG4]?
    2. 为什么我从不同的编译器甚至从同一个编译器得到不同的结果?这使我认为标准在这种情况下并没有指定行为.

    谢谢您的任何建议,评论和标准解释.

    Thank you for any suggestions, comments and standard interpretations.

    更新
    我想了解编译器的行为.更准确地说,如果违反了ODR,为什么不生成任何错误.一个假设是,由于 UsedClass1 UsedClass2 类中的所有函数都被标记为内联(因此,未违反C ++ 03 3.2),因此链接器不会报告错误,但是在这种情况下,输出[EG1],[EG3],[EG4]看起来很奇怪.

    Update
    I would like to understand the compiler's behaviour. More precisely, why there are no errors generated if the ODR is violated. A hypothesis is that since all functions in classes UsedClass1 and UsedClass2 are marked as inline (and therefore C++03 3.2 is not violated) the linker doesn't report errors, but in this case outputs [EG1], [EG3], [EG4] seem strange.

    推荐答案

    这是该规则禁止使用的规则(C ++ 11措辞),来自标准的3.2节:

    This is the rule that prohibits what you're doing (the C++11 wording), from section 3.2 of the Standard:

    一个类类型的定义(第9条),枚举类型(7.2),具有外部链接的内联函数(7.1.2),类模板(第14章),非静态函数模板(14.5.6),类模板的静态数据成员(14.5.1.3),类模板的成员函数(14.5.1.1)或针对某些模板的模板专门化如果每个定义出现在不同的翻译单元中,并且定义满足以下要求,则在程序中未指定参数(14.7,14.5.5).给定一个在多个翻译单元中定义的名为D的实体,则

    There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

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

    • each definition of D shall consist of the same sequence of tokens; and

    ,按照3.4查找的对应名称,应指代D定义内定义的实体,或应指代重载解析后的同一实体(13.3 )和部分模板特殊化(14.8.3)匹配之后,除非名称可以引用具有内部链接或不具有链接的const对象,如果该对象在D的所有定义中具有相同的文字类型,并且该对象用常量表达式(5.19)初始化,并使用对象的值(而不是地址),并且该对象在D的所有定义中都具有相同的值;和

    in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D; and

    ,相应的实体应具有相同的语言链接;和

    in each definition of D, corresponding entities shall have the same language linkage; and

    ,所引用的重载运算符,对转换函数,构造函数,运算符新函数和运算符delete函数的隐式调用,均应引用同一函数或内部定义的函数D的定义;和

    in each definition of D, the overloaded operators referred to, the implicit calls to conversion functions, constructors, operator new functions and operator delete functions, shall refer to the same function, or to a function defined within the definition of D; and

    都将(隐式或显式)函数调用使用的默认参数视为其令牌序列出现在D的定义中;也就是说,默认参数要遵守上述三个要求(并且,如果默认参数具有带有默认参数的子表达式,则该要求将递归地应用).

    in each definition of D, a default argument used by an (implicit or explicit) function call is treated as if its token sequence were present in the definition of D; that is, the default argument is subject to the three requirements described above (and, if the default argument has sub-expressions with default arguments, this requirement applies recursively).

    如果D是具有隐式声明的构造函数(12.1)的类,则好像该构造函数是在odr使用的每个翻译单元中隐式定义的,并且在每个翻译中均隐含定义单元应为基类或D的类成员调用相同的构造函数.

    if D is a class with an implicitly-declared constructor (12.1), it is as if the constructor was implicitly defined in every translation unit where it is odr-used, and the implicit definition in every translation unit shall call the same constructor for a base class or a class member of D.

    在您的程序中,您违反了class UsedClass的ODR,因为令牌在不同的编译单元中是不同的.您可以通过将UsedClass::doit()的定义移到类主体之外来解决此问题,但是相同的规则也适用于内联函数的主体.

    In your program, you're violating the ODR for class UsedClass because the tokens are different in different compilation units. You could fix that by moving the definition of UsedClass::doit() outside the class body, but the same rule applies to the body of inline functions.

    这篇关于C ++:在不同的翻译单元中具有相同名称的不同类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆