给出以下代码
class T {
public:
virtual ~T () {}
virtual void foo () = 0;
};
class U {
public:
U() {}
~U() {}
void bar () { std::cout << "bar" << std::endl; }
};
class A : public U, public T {
public:
void foo () { std::cout << "foo" << std::endl; }
};
int main () {
A * a = new A;
std::vector<U*> u;
std::vector<T*> t;
u.push_back(a);
t.push_back(reinterpret_cast<T*>(u[0]));
u[0]->bar ();
t[0]->foo ();
delete a;
return 0;
}
我得到了我期望的输出
bar
foo
但是,如果我将U
的定义更改为
class U {
public:
U() {}
virtual ~U() {}
virtual void bar () { std::cout << "bar" << std::endl; }
};
我仍然编译正常,没有警告/错误,但现在输出
bar
bar
虚拟声明是什么阻止我调用foo
?
答案 0 :(得分:4)
首先,您的示例中没有虚拟基类。包含虚函数的类称为 polymorphic 。 (在C ++中有“虚拟基类”这样的东西,但它与你的例子无关。)
其次,代码的行为不依赖于任何虚拟声明。您已使用reinterpret_cast
故意破坏了基指针的完整性。因此,代码的行为是 undefined 。
从一个基指针到另一个指针的直接转换(这是你在代码中尝试做的)被称为交叉投射。 C ++中唯一可以进行交叉投射的演员是dynamic_cast
。
t.push_back(dynamic_cast<T *>(u[0]));
您可以在没有dynamic_cast
的情况下执行间接交叉投射,但为此必须先使用A *
向下转换指向派生类型的指针(static_cast
),然后将其上转换为另一个基指针类型
t.push_back(static_cast<A *>(u[0])); // upconversion to `T *` is implicit
答案 1 :(得分:1)
如果您使用reinterpret_cast
,您将失去所有保证,而您所做的任何事情都是“未定义的行为”。在这种情况下,我预计VMT会搞砸,或者VPTR会被覆盖。
作为一个例子,当我编译上面的第一个代码时,我在编译器上执行了段错误。
如果你真的想要“交叉执行”,你应该从一个公共基类派生,并通过U和T 虚拟(: virtual public
)继承该基类,或者使用{ {1}}代替dynamic_cast
。
答案 2 :(得分:0)
像t
一样填充u
:
t.push_back(a);
您不需要reinterpret_cast
,因为A
是T
。