从基类转换为派生的未定义行为吗?

Vin*_*rta 1 c++ class derived-class

我遇到了一个问题,即派生到派生类会解决问题.我在SO上找到了一个答案,说它可以导致UB,测试它,它编译和正常工作.是不确定的行为?如果这是解决这个问题的正确方法?

class A
{
public:
    A(){};
    ~A(){}
};

class B : public A
{
public:
    B(){};
    ~B(){}
    void Show() { std::cout << "Show" << std::endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;
    B* b = static_cast<B*>(&a);
    b->Show();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

In *_*ico 8

只要指向基类型的指针实际上指向派生类型的实例,那么根据C++标准,这种用法不是未定义的.但是,在您的代码示例中,指针b不指向其实例B或其任何派生类型(没有),它指向的实例A.所以你的代码实际上会调用未定义的行为.

我在SO上找到了一个答案,说它可以导致UB,测试它,它编译和正常工作.

某些代码编译和正常工作的事实并不排除代码调用未定义行为的可能性,因为未定义的行为包括"似乎工作".您应该避免未定义行为的原因是因为无法保证它在下次调用UB时的工作方式相同.

是不确定的行为?如果这是解决这个问题的正确方法?

在您的示例中,是的,它是未定义的行为.正确的方法取决于您的代码实际应该做什么,因为您提供的示例充其量只是一个学术范例.

为清楚起见,对main()函数的以下修改具有明确定义的行为,并且C++标准明确允许:

B objectB;
A* ptrA = &objectB;

B* b = static_cast<B*>(ptrA);
b->Show();
Run Code Online (Sandbox Code Playgroud)

在这里,它被很好地定义,因为指针ptrA实际指向一个实例B,即使指针本身具有类型A*.在上述例子中,从铸造A*B*随后调用的一个B上铸造指针将工作的功能.不同之处在于,在您的问题中的示例中,b实际上并未指向实例B.


相关条款(强调我的):

C++标准5.2.9/8静态强制转换[expr.static.cast]

类型"指向cv1的 指针"的rvalue B,其中B是一个类类型,可以转换为类型为"指向cv2的 指针"的rvalue D,其中D是一个派生类(第10节)B,如果是从"指针到"的有效标准转换D"到'指针B’的存在(4.10),CV2是相同的 CV企业资质如,或更大CV企业资质比,CV1,并且B不是虚拟基类D.空指针值(4.10)将转换为目标类型的空指针值.如果类型的右值"指针CV1 B"指向一个B实际上是类型的对象的子对象D,将得到的指针指向类型的包围对象D.否则,演员的结果是不确定的.