当转换为完全不同的类时,static_cast 的行为如何?

Posted

技术标签:

【中文标题】当转换为完全不同的类时,static_cast 的行为如何?【英文标题】:How does static_cast behave when cast to a totally different class? 【发布时间】:2020-07-05 10:08:06 【问题描述】:

我正在做一些练习来学习 C++ 中的继承和虚拟方法。 所以我发现自己是这样的:

class A
public:
    virtual void f() const cout << "A::f";
    virtual void g() cout << "A::g"; m();
    virtual void h() cout << "A::h"; f();
    void m() cout << "A::m"; f();
    virtual A* n()  cout << "A::n"; return this;


class B : public A
public:
    virtual void f() const cout << "B::f"; //override
    void g() cout << "B::g"; A::n(); //override
    virtual void m() cout << "B::m"; f();
    A* n()  cout << "B::n"; return this;


class C : public A
public:
    virtual void f() cout << "C::f"; //new method cause misses const
    void g() const cout << "C::g"; m(); //new method cause added const
    void m() cout << "C::m"; g(); f();




***
A*q3 = new C();
(static_cast<B*>(q3->n()))->f(); //solution is A::n  A::f
***

那么这是书中的错误还是正确的?对我来说,据我所知,我会将其标记为“未定义的行为”,但如果我错了,这是如何工作的?

【问题讨论】:

“那么这是书中的错误还是正确的?” - 这本书到底说了什么? is this an error from the book 这样的代码在书里吗?你介意分享一下那是什么书吗? 代码无法编译 这个练习的目的是告诉输出将是什么:如果它编译,那么控制台输出会是什么,如果不编译,则制作为“NC”,如果有运行时错误/未定义的行为然后标记为“?”。我不拥有这本书,它是我的教授分享的部分(我不知道名字或其他),我评论的是提供的解决方案。 【参考方案1】:

From cplusplus.com:

static_cast 可以在指向相关的指针之间进行转换 类,不仅从派生类到它的基类,而且还从一个 基类为其派生。这确保了至少类是 如果转换了正确的对象,则兼容,但 没有安全检查 在运行时执行以检查正在转换的 对象是否在 实际上是目标类型的完整对象。因此,这取决于 程序员确保转换是安全的。另一方面, 避免了 dynamic_cast 的类型安全检查的开销。

您可以轻松地转换为具有比原始对象更多字段的对象,尽管您指向的真实对象更短。然后,当您尝试访问这些字段时,就像缓冲区溢出一样 - 会产生非常令人惊讶的结果。这样做时要非常小心。

【讨论】:

【参考方案2】:

这会将C* 对象转换为A* 对象(通过n()),然后将A* 对象转换为B* 对象。最后它调用了一个virtual函数。

那么在实践中会发生什么?编译器将查看底层对象的虚拟表并在那里找到要调用的函数f。虚拟表是内存中的实际表。所以从 A 到 B 到 C 的所有转换对表中的数据没有影响。 没有未定义的行为,确实会调用A::f

但是,这只适用于虚拟函数。如果代码要使用 C 对象调用 B 的成员函数,并且如果该函数要使用 B 中可用但 C 中不可用的成员数据,那么一切都会崩溃。欢迎使用 C++,在 C++ 中,向自己的脚开枪是一个理想的功能。

【讨论】:

不太确定 UB 声明。该标准在 [expr.static.cast] (C++17: 5.2.9(11)) 中说:“如果“指向 cv1 B”的指针类型的纯右值指向实际上是一个对象的子对象的 B类型 D,结果指针指向类型 D 的封闭对象。否则,行为未定义。我将其解读为:对象实际上必须是强制转换类型或派生类型,否则将调用 UB。”在存在似乎合理要求的去虚拟化优化器的情况下。 但是如果这个工作是因为你解释的原因,那么这个也是一样的吗? (static_cast&lt;C*&gt;(q2))-&gt;g(); //soulution is "?" (undefined behaviour/run time error) 其中 q2 是 A*q2 = new B(); 我想我会回答自己再次阅读这个If the code were to call a member function of B using a C object, and if that function were to make use of member data available in B but not in C, all hell will break loose

以上是关于当转换为完全不同的类时,static_cast 的行为如何?的主要内容,如果未能解决你的问题,请参考以下文章

C++:类型转换

为啥当我没有为我的 openGLWidget 创建额外的类时 glRotate 只工作一次?

当嵌入为文本输入边框样式的类时,如何在 flex 中平滑嵌入的图像

Stylus:当一个元素有一个额外的类时,我怎样才能改变它的颜色?

static_cast<std::u16string> 的 GCC 问题

向上转换到基类时如何使用继承的类成员的值