【发布时间】:2021-10-06 19:43:28
【问题描述】:
#include <iostream>
struct A {
virtual void a() {
puts("A");
}
};
struct B {
virtual void b() {
puts("B");
}
};
struct C {
virtual void c() {
puts("C");
}
};
struct D : public A, public B, public C {
virtual void c() {
C::c();
puts("cd");
}
};
int main() {
A* obj = new D;
obj->a();
B* b = (B*)obj;
b->b();
C* c = (C*)obj;
c->c();
return 0;
}
我有这段代码,我有非虚拟多重继承。但是,当我调用主函数中的函数时,似乎调用了错误的虚函数。 而不是输出:
A
B
C
cd
它输出:
A
A
A
让我困惑的是,当我将代码更改为这样做时:
B* b = (B*)(D*)obj;
b->b();
C* c = (C*)(D*)obj;
c->c();
它输出我所期望的(见上文)。 Afaik 像这样进行双指针转换不会产生任何影响,并且会被编译器优化。但它似乎正在改变正在调用的虚函数。
有人能解释一下为什么这会改变调用的虚函数吗?
注意事项:
我在每一步都打印了指针,它们是一样的。
我想避免使用dynamic_cast(尽管它确实有效),因为它对于我需要它做的事情来说太慢了。
【问题讨论】:
-
您不能将
A*转换为C*,它们不是相关的类。这大概是UB -
C 风格转换不安全的另一个原因。
dynamic_cast慢在哪个世界?它的开销不超过一次虚拟调用。 -
(B*)(D*)转换是正确的,因为它将指针转换为指向D的指针,并且编译器知道如何将D*转换为B*。只有知道obj实际上是一个指向D类型对象的子对象的指针,您才能这样做。如果您总是知道这一点,那么演员阵容就可以了。如果你不能确定,那么dynamic_cast<B*>(obj)会做对的。 -
重新打开。关于为什么直接转换不起作用的重复是相关的,但没有说明为什么
(D*)(B*)转换起作用。 -
即使你不想使用
dynamic_cast,你也应该使用static_cast。编译器会告诉您,您无法将A *转换为C *,因此您需要分两步完成。第二个演员,也没有必要,因为可以很容易地写static_cast<D *>(obj)->b();。
标签: c++ virtual-functions