当转换为完全不同的类时,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<C*>(q2))->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 的行为如何?的主要内容,如果未能解决你的问题,请参考以下文章
为啥当我没有为我的 openGLWidget 创建额外的类时 glRotate 只工作一次?
当嵌入为文本输入边框样式的类时,如何在 flex 中平滑嵌入的图像
Stylus:当一个元素有一个额外的类时,我怎样才能改变它的颜色?