将指针转换为不同的指针会导致调用错误的虚函数

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::aB::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.

这似乎很难相信。