危险的演员

Dangerous Cast?

本文关键字:危险      更新时间:2023-10-16

考虑一下:

#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 ?
}

这段代码可以工作使用它有什么危险?

在C和c++中,通过对另一类型对象的指针或引用来解引用一种类型的对象通常是未定义的行为(读作"非法但编译器允许")(少数例外,如通过对基类的指针访问)。这叫做严格混叠规则。

在这里阅读更多:什么是严格的混叠规则?

你的代码违反了这条规则,通过指向类型b的指针访问类型A的对象


请注意,编译器通常无法验证静态强制转换(在您的情况下,c强制转换相当于static_cast)。如果您不确定对象类型,dynamic_cast将在运行时验证强制转换是否合法,而static_cast仅在编译时检查,并允许一些不正确的强制转换。

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

危险的是有一个指向A的指针,你通常不确定它是B还是C的派生类实例。

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

c++是一门足以让你自己和房间里的每个人上吊的语言!

我的观点是,您应该尽可能少地使用强制转换,并且只在极少数情况下使用。

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

实际上代码只有看起来可以工作。通过告诉编译器您有一个B,而实际上只有一个A(父类),您调用了未定义的行为。它可能随时中断,即使使用相同的编译器。

假牙是在这样的场景(我相信还有更多):

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;

它将工作(很可能),但这是不好的做法,基本上是未定义的代码。