在阅读Essential c ++第5.10章运行时类型识别时,我遇到了一个问题。先介绍一下背景知识。有一个名为num_sequence
的基类和一个来自Fibonacci
的类num_sequence
。在基类中,有一个名为gen_elems
的虚函数,派生类有自己的定义。
以下内容来自本书。
Fibonacci fib;
num_sequence *ps = &fib;
ps->gen_elems(64);
我们知道将调用gen_elems()的Fibonacci实例。 然而,虽然我们从这个测试中知道ps解决了Fibonacci class对象,试图调用Fibonacci实例 gen_elems()直接通过ps导致编译时错误:
PS->斐波那契:: gen_elems(64); //给出编译时错误
ps不知道它所解决的对象的类型,即使我们和typeid和虚函数机制也是如此。
要调用gen_elems()的Fibonacci实例,我们必须指示编译器将
ps
转换为Fibonacci类型的指针。 static_cast和dynamic_cast都可以完成这项工作。< / p>
我对这句大胆的句子感到困惑。 ps->gen_elems(64)
实际上调用了gen_elems()
的Fibonacci实例。为什么需要我们使用static_cast和dynamic_cast将其转换为Fibonacci类型的指针?
答案 0 :(得分:4)
在大多数情况下,您只需正常调用虚方法,让多态执行其工作,根据需要调用派生最多的实现。作者试图解释的是,也可以在不经过多态的情况下直接调用虚拟方法的特定实现。
假设某个类派生自Fibonacci
以再次覆盖gen_elems()
,但您不想调用该覆盖,而是要调用Fibonacci
覆盖。通过在编译时将num_sequence
指针转换为Fibonacci
指针(或后代指针),它允许编译器访问Fiboncci
vtable,以便它可以发出代码直接调用{{ 1}}(如果在运行时指向的对象实际上不是Fibonacci::gen_elems()
或后代的实例,则可能会崩溃/损坏您的应用程序。这在编译时无法验证。)
例如:
Fibanocci
class num_sequence
{
public:
virtual void gen_elems(int value)
{
std::cout << "num_sequence" << std::endl;
}
};
class Fibonacci : public num_sequence
{
public:
void gen_elems(int value)
{
std::cout << "Fibonacci" << std::endl;
}
};
class SomethingElse : public Fibonacci
{
public:
void gen_elems(int value)
{
std::cout << "SomethingElse" << std::endl;
}
};