【问题标题】:using dynamic_cast for runtime type identification使用 dynamic_cast 进行运行时类型识别
【发布时间】:2013-02-09 02:35:44
【问题描述】:

在阅读 Essential c++ 第 5.10 章运行时类型识别时,我遇到了一个问题。我先介绍一下背景。有一个名为num_sequence 的基类和一个派生自num_sequence 的类Fibonacci。在基类中,有一个名为gen_elems 的虚函数,派生类有自己的定义。

以下内容来自本书。

Fibonacci fib;
num_sequence *ps = &fib;
ps->gen_elems(64);

我们知道 gen_elems() 的斐波那契实例将被调用。 然而,尽管我们从这个测试中知道 ps 解决了斐波那契 类对象,尝试调用 Fibonacci 实例 gen_elems() 直接通过 ps 会导致编译时错误:

ps->斐波那契::gen_elems(64); //给出编译时错误

ps 不知道它所寻址的对象的类型,即使我们和 typeid 和虚函数机制知道。

要调用 gen_elems() 的 Fibonacci 实例,我们必须指示编译器将 ps 转换为 Fibonacci 类型的指针。 static_cast 和 dynamic_cast 都可以完成这项工作。

我被粗体字弄糊涂了。 ps->gen_elems(64) 实际上调用了gen_elems() 的斐波那契实例。为什么需要使用 static_cast 和 dynamic_cast 将其转换为斐波那契类型的指针?

【问题讨论】:

    标签: c++ dynamic-cast static-cast


    【解决方案1】:

    大多数情况下,您只需正常调用虚方法,并让多态根据需要调用最派生的实现即可。作者试图解释的是,也可以不经过多态直接调用虚方法的特定实现。

    假设一个类派生自Fibonacci 以再次覆盖gen_elems(),但您不想调用该覆盖,您想调用Fibonacci 覆盖。通过在编译时将num_sequence指针转换为Fibonacci指针(或后代指针),它允许编译器访问Fiboncci vtable,因此它可以发出代码直接调用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;
      }
    };
    

    .

    num_sequence ns;
    Fibonacci fib;
    SomethingElse se;
    num_sequence *ps;
    
    ps = &ns;
    ps->gen_elems(64); // displays "num_sequence"
    
    ps = &fib;
    ps->gen_elems(64); // displays "Fibonacci"
    
    ps = &se;
    ps->gen_elems(64); // displays "SomethingElse"
    
    ps->Fiboacci::gen_elems(64); // compiler error!
    
    static_cast<Fibonacci*>(ps)->Fibonacci::gen_elems(64); // displays "Fibonacci"
    static_cast<SomethingElse*>(ps)->Fibonacci::gen_elems(64); // displays "Fibonacci"
    
    Fibonacci *pfib = dynamic_cast<Fibonacci*>(ps);
    if (pfib != NULL)
    {
        pfib->gen_elems(64); // displays "SomethingElse"
        pfib->Fibonacci::gen_elems(64); // displays "Fibonacci"
    }
    

    【讨论】:

    • 赞成,因为 Remy 是对的,但我希望我可以反对 Lippman(Essential C++ 的作者)。简短的回答是“如果你不是初学者,你可能想做[一些相当神秘的事情。]”他应该知道不要在这里介绍这些东西,我很惊讶他这样做了,因为通常他的东西是很棒。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    相关资源
    最近更新 更多