将extern变量声明为基类和派生类指针

时间:2013-06-18 13:18:33

标签: c++ c++builder extern

假设我们遇到这样的情况:

base.h:

class Base { };

derived.h:

#include "base.h"
class Derived : public Base { };
extern Derived *variable;

derived.cpp:

#include "derived.h"
Derived *variable; 

在otherwise.cpp中将variable声明为Base的指针是否正确?

class Base;
extern Base *variable;

C ++ Builder链接器没有抱怨,一切似乎都有效。根据标准,这是安全和正确的,还是variable的每个声明都属于同一类型?

3 个答案:

答案 0 :(得分:2)

不行。如果名称variable应该引用同一个实体(因为它是extern),那么它必须具有相同的类型。否则,您将违反ODR(一个定义规则)。

答案 1 :(得分:2)

以下是一些可能出错的方法(除了未定义的行为,这意味着您甚至不应该依赖其中一种行为):

  • 编译器可能会将变量的类型作为变量的一部分。显然C ++ Builder没有,但我很确定MSVC的确如此。如果是,则会出现链接器错误。
  • 假设在某些时候Derived更改为

    class Derived : public Something, public Base {};

    其中Something不为空,那么在大多数ABI中,当Derived*转换为Base*时,Base*会更改其值。但是,全局变量的别名会绕过此调整,从而使Base不会指向OtherDerived

  • 编译器实际上可能通过其他方式检测到您的ODR违规,并且只是出错。

  • 如果您将Base类型的对象(也来自Derived,而不是variable)分配给Derived*,会发生什么?程序中将其视为Derived的部分期望它指向OtherDerived,但它确实指向foo。你可以在这样的代码中看到最迷人的效果。您可以进行设置,以便在Derived调用foo2版本时调用虚拟函数OtherDerived调用{{1}}版本。可能性无穷无尽。

答案 2 :(得分:1)

当然不行。

在某些情况下会产生歧义:

// Example Function:
void do_stuff(Base* b);

// Code
do_stuff(variable); // You could mean Derived* or Base*.
                    // You would write the same thing, but mean 
                    // 2 different things.