覆盖?向上转型?

3
以下代码存在一个错误:最后一行应该是
bp->g();
问题是,如果我注释掉那行,bp->f() 实际上调用的是 Derived 版本,所以我假设编译器将 bp 视为 Derived 类型,那么为什么在调用 g 时,编译器将 bp 视为基类指针。

谢谢!
#include <iostream>
using namespace std;

class Base {
public:
    virtual void f() const { cout << "Base::f()\n"<< endl; }
    virtual void g() const { cout << "Base::g()\n"<< endl; }
};

class Derived : public Base {
public:
    void f() const {cout << "Derived::f()" << endl; }
    void g(int) const {cout << "Derived::g()" << endl; }
};

int main() {
    Base* bp = new Derived;
    bp->f();
    bp->g(1);
}

在 Drived 类中 void g(int ??) 缺少变量名。 - Grijesh Chauhan
@GrijeshChauhan 变量未被使用,因此不需要名称。 - juanchopanza
@juanchopanza 好的,我刚刚注意到了。 - Grijesh Chauhan
1
你只能从指向 Base 的指针调用 Base 的公共接口中的方法,但是这些调用会分派到派生类型。 - juanchopanza
4个回答

4
您不能通过更改其参数来覆盖虚成员函数。也就是说,Derived::g(int)并没有覆盖Base::g()
想象一下您是编译器。您看到函数调用bp->g(1),并且您知道bp是一个Base*。因此,您查找Base中名为g且参数为int的函数。您找到了什么?什么都没有。
只有在基类中找到一个函数是虚函数,它才会考虑对象的动态类型。因此,让我们考虑调用bp->f()。它知道bp是一个Base*,因此它查找不带参数的Base成员函数f。当然,它找到了Base::f(),并发现它是虚拟的。因为它是虚拟的,所以它会在对象的动态类型Derived中查找相同的函数。它找到了Derived::f(),并调用了它。

1
这是因为Derived::g没有覆盖Base::g。它是一个完全独立的方法,恰好有相同的名称。这两个方法是无关的,因为它们接受不同的参数。
因此,当您调用bp->g(1)时,Base也恰好有一个名为g的方法是完全无关紧要的。

0

你的派生类现在不再覆盖 Base::g()

class Derived : public Base {
public:
//...
    void f() const {cout << "Derived::f()" << endl; }
    void g() const {cout << "Derived::g()" << endl; } // <- add this, it is overriding Base::g() const
//...
};

该方法:void g(int) const {cout << "Derived::g()" << endl; } 是您的派生类的自主方法,它不会覆盖Base::g,因为Base::g没有使用int参数。


0
实际上,您的示例应该在bp->g(1)行中给出编译时错误。在这两种情况下,编译器将bp视为具有2个虚函数void f()和void g()的Base*,其中f()在Derived中被覆盖,因此当您调用bp->f()时,通过vtable将调用Derived版本。但是,在Base中没有void g(int),因此bp->g(1)会导致编译时错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接