将指针转换为不同的指针会导致调用错误的虚函数
Casting pointer to different pointer causes wrong virtual function to be called
#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
(尽管它确实有效),因为它对于我需要它做的事情来说太慢了。
Can someone explain why this would change what virtual function is being called?
通常,指针类型之间的 C 风格转换不会更改指针的值,因此不会产生任何影响。但是,有一个例外。
class 与父项或子项 class 之间的转换可以更改指针的值。例如:
class A
{ int a; };
class B
{ int b; };
class C : public A, public B
...
现在,指向 class A
实例的指针可能与指向其 a
成员的指针和指向 [=44] 实例的指针具有相同的值=] B
可能与指向其 b
成员的指针具有相同的值。指向 class C
实例的指针不能与指向其 A::a
和 B::b
成员的指针具有相同的值,因为它们是不同的对象。
需要 B*
的函数可以传递 C*
,因为 C
是 B
。类似地,出于同样的原因,可以向需要 A*
的函数传递 C*
。但至少其中之一需要更改指针的值。
因此这些类型之间的转换 将 更改值,其他都是空操作。
当然,这都是UB。您在不相关的类型之间进行转换,然后取消引用它们。
I want to avoid using dynamic_cast (although it does work) as it's too slow for what I need it to do.
这似乎很难相信。
#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
(尽管它确实有效),因为它对于我需要它做的事情来说太慢了。
Can someone explain why this would change what virtual function is being called?
通常,指针类型之间的 C 风格转换不会更改指针的值,因此不会产生任何影响。但是,有一个例外。
class 与父项或子项 class 之间的转换可以更改指针的值。例如:
class A
{ int a; };
class B
{ int b; };
class C : public A, public B
...
现在,指向 class A
实例的指针可能与指向其 a
成员的指针和指向 [=44] 实例的指针具有相同的值=] B
可能与指向其 b
成员的指针具有相同的值。指向 class C
实例的指针不能与指向其 A::a
和 B::b
成员的指针具有相同的值,因为它们是不同的对象。
需要 B*
的函数可以传递 C*
,因为 C
是 B
。类似地,出于同样的原因,可以向需要 A*
的函数传递 C*
。但至少其中之一需要更改指针的值。
因此这些类型之间的转换 将 更改值,其他都是空操作。
当然,这都是UB。您在不相关的类型之间进行转换,然后取消引用它们。
I want to avoid using dynamic_cast (although it does work) as it's too slow for what I need it to do.
这似乎很难相信。