【问题标题】:What happens if i have the same function prototype in a derived class?如果我在派生类中有相同的函数原型会怎样?
【发布时间】:2021-05-04 18:09:09
【问题描述】:

我有一个使用继承的非常简单的代码,并且在我的基类和派生类中有相同的函数原型。我不明白最后一个结果(pB->bar()),因为我认为由于pB 指向派生类型对象(在delete 之后)它应该调用D::bar()

#include <iostream>
class B {
    public:
        virtual void foo() { std::cout << "B:foo" << std::endl; }
        void bar() { std::cout << "B:bar" << std::endl; }
};

class D : public B {
    public:
        virtual void foo() override { std::cout << "D:foo" << std::endl; }
        void bar(){ std::cout << "D:bar" << std::endl;}
};

int main() {
    B* pB = new B;
    pB->foo();
    pB->bar();
    delete pB;
    pB = new D;
    pB->foo();
    pB->bar();
    delete pB;
}

这样做的结果是:

B:foo
B:bar
D:foo
B:bar

【问题讨论】:

  • 您认为virtual 关键字究竟是干什么用的?
  • 如果您想了解更多关于它的行为方式以及virtual 关键字如何影响为方法分派生成的程序集的更多信息,您应该探索一个有趣的主题是 vtable 查找。

标签: c++ inheritance


【解决方案1】:

您已将virtual 用于foo,但未使用bar。该程序演示了该关键字的效果:它表示考虑对象的动态或运行时类型。没有它,编译器将仅使用静态或编译时类型信息生成直接函数调用。

【讨论】:

    【解决方案2】:

    关键字virtual为类函数创建一个虚表,然后当你使用一个指向类的指针时,程序会检查类的类型并尝试在虚表中找到函数foo。

    当你调用 bar 时,程序会检查类指针是否实现了 bar,因为指针是 B 类型,所以会调用 B 的函数 bar。

    你可以写

    D* pD = new D;
    pD->bar();
    

    【讨论】:

      【解决方案3】:

      bar() 不是virtual,因此对它的调用在编译时使用调用它的类型静态解析。它不会像您期望的那样在运行时动态解析,类似于foo(),即virtual

      通过B* 指针调用bar() 将调用B::bar(),而通过D* 指针调用它将调用D::bar()pB 是一个B*,这就是为什么pB-&gt;bar() 调用B::bar() 而不管pB 是指向B 还是D 对象。这是一个静态调用。

      【讨论】:

        猜你喜欢
        • 2021-03-20
        • 1970-01-01
        • 2015-04-11
        • 2019-06-22
        • 2017-01-11
        • 2012-06-21
        • 1970-01-01
        • 2020-03-22
        • 1970-01-01
        相关资源
        最近更新 更多