危险的演员?

时间:2011-12-08 14:26:25

标签: c++ oop pointers

考虑一下:

#include <iostream>
using namespace std;
class A{
   protected:
       void some_function(int params)
       {
        //inside A: do something A related 
       }
};

class B: public A{
public:
    void call_some_function(int params)
    {
    some_function(params); // Simple call to A::some_function and NOTHING MORE.
    }
};


int main(int argc, char *argv[])
{
   A* a = new A();

   ((B*)(a))->call_some_function(20); // Is it OK ?
}

此代码有效 使用它有什么危险?

7 个答案:

答案 0 :(得分:6)

在C和C ++中,它通常是未定义的行为(读作&#34;非法,但允许编译器&#34;)通过指针或引用取消引用一种类型的对象另一种类型的对象(除了通过指向基类的指针访问外)。这称为严格别名规则。

在此处阅读更多内容:What is the strict aliasing rule?

您的代码违反了此规则,方法是通过指向B类型的指针访问A类型的对象。


请注意,编译器通常无法验证您的静态强制转换(在您的情况下,C-cast等同于static_cast)。如果你不确定对象类型,dynamic_cast来验证演员在运行时是否合法,而不是仅在编译时检查并允许一些不正确的演员表的static_cast。 / p>

答案 1 :(得分:1)

危险在于指向A时,您通常不确定它是B还是C派生类实例。

答案 2 :(得分:1)

可能 - 取决于编译器如何为对象安排内存。

C ++是一种语言,它提供了足够多的绳索来悬挂自己和房间里的其他人!

我的观点是你应该尽可能少地使用演员阵容,并且只在极少数情况下使用。

答案 3 :(得分:1)

一个危险是call_some_function只能调用A中的函数(或一般的访问成员)。对B成员的所有访问都将导致在分配的内存之外访问,可能会带来灾难性的后果。

答案 4 :(得分:1)

这是未定义的行为,所以任何事情都可能发生。在实践中,你 只要涉及单一继承,就可以逃脱它, 但总的来说,你不能指望它;调试实现可以​​, 例如,在B::call_some_function中生成代码以确保代码 作为this传递的地址对应于B类型的对象 实际上存在于程序中。

答案 5 :(得分:1)

实际上只有的代码才能显示才能正常工作。当您真正只有B(父类)时,通过告诉编译器您有A来调用未定义的行为。即使使用相同的编译器,它也可能随时中断。

答案 6 :(得分:0)

这种情况就像这样(并且我确定更多):

class B: public A{
public:

    int local_var;

    void call_some_function(int params)
    {
        local_var = 5; // IN HERE.
        some_function(params); // Simple call to A::some_function and NOTHING MORE.
    }
};

在这种情况下,它将尝试访问未定义的var(local_var)。

就像:

struct A {
int i1;
int i2;
}

struct B {
int i1;
int i2;
int i3;
}

A a;
(B)a.i1 = 2;

它会起作用(最有可能),但这是不好的做法,基本上是未定义的代码。