从基类转换为派生类是未定义的行为吗? [英] Is it undefined behavior to cast from base class to derived?

查看:87
本文介绍了从基类转换为派生类是未定义的行为吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个问题,即强制转换为派生类可以解决该问题。我在S.O上找到了一个答案,说它可以导致UB,对其进行测试,编译并可以正常工作。它是未定义的行为吗?

I've encountered myself in a problem where casting to the derived class would solve the problem. I've found an answer on S.O that says it can lead to UB, testing it, it both compiled and worked correctly. Is it undefined behavior? If it is what would be a correct approach to this problem?

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;
}


推荐答案

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

As long as the pointer to a base type actually points to an instance of a derived type, then such usage is not undefined according to the C++ standard. However, in your code sample, the pointer b does not point to an instance of B or any of its derived types (which there are none), it points to an instance of A. So your code does in fact invoke undefined behavior.


我在SO上找到了一个答案,说它可以导致UB,对其进行测试,
都可以编译并正常工作。

I've found an answer on S.O that says it can lead to UB, testing it, it both compiled and worked correctly.

某些代码可以正确编译并正常工作的事实并不排除可能性调用未定义行为的代码,因为未定义行为包括似乎可以正常工作。之所以要避免未定义的行为,是因为无法保证它在下次调用UB时将以相同的方式起作用。

The fact that some code compiles and works correctly does not rule out the possibility of code invoking undefined behavior, because undefined behavior includes "appears to work". The reason why you should avoid undefined behavior is because there's no guarantee that it will work the same way the next time you invoke UB.


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

Is it undefined behavior? If it is what would be a correct approach to this problem?

在您的示例中,这是未定义的行为。正确的方法取决于您的代码实际应该执行的操作,因为您提供的示例充其量只是一个学术示例。

In your sample, yes, it is undefined behavior. The correct approach would depend on what your code is actually supposed to do, as the example you provide is an academic example at best.

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

To make it clear, the following modification to your main() function has well-defined behavior and is explictly allowed by the C++ standard:

B objectB;
A* ptrA = &objectB;

B* b = static_cast<B*>(ptrA);
b->Show();

在这里,它的定义很明确,因为指针 ptrA 实际上指向 B 的实例,即使指针本身的类型为 A * 。在上面的示例中,将 A * 转换为 B * ,然后调用 B 在强制转换指针上的功能将起作用。区别在于,在您问题的示例中, b 实际上并不指向 B 的实例。

Here, it's well defined because the pointer ptrA actually points to an instance of B, even though the pointer itself has type A*. In the above example, casting from A* to B* then invoking one of B's functions on the casted pointer will work. The difference is that in the example in your question, b does not actually point to an instance of B.

相关条款(强调我的意思):

The relevant clause (emphasis mine):


类型为指向 cv1 <的指针的右值/ em> B ,其中 B 是类类型,可以将
转换为右值键入指向 cv2 D 的指针,其中 D
类如果有效的标准转换是从
指针到 D 转换为 B (第10条) 存在指向 B 的指针
(4.10), cv2 是相同的
cv -emqual等于或大于 cv1 B cv 资格是
不是虚拟的 D 的基类。空指针值(4.10)是
转换为目标类型的空指针值。 如果类型为指向cv1 B 的指针的
右值指向 B 实际上是对象 D
子对象,结果指针指向类型为 D的
封闭对象
。否则,强制转换的结果为
未定义。

An rvalue of type "pointer to cv1 B", where B is a class type, can be converted to an rvalue of type "pointer to cv2 D", where D is a class derived (clause 10) from B, if a valid standard conversion from "pointer to D" to "pointer to B" exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D. The null pointer value (4.10) is converted to the null pointer value of the destination type. If the rvalue of type "pointer to cv1 B" points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.

这篇关于从基类转换为派生类是未定义的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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