2013-04-07 98 views
3

下面的代码有错误:最后一行应该是
bp->g();
的问题是,如果我注释掉该行,bp->f()实际上调用派生版本,所以我想作为类派生的编译器对待BP,那么为什么当调用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); 
} 
+0

在Drived类'void g(int ??)'变量名缺失。 – 2013-04-07 15:59:40

+0

@GrijeshChauhan该变量未使用,因此不需要名称。 – juanchopanza 2013-04-07 16:00:27

+0

@juanchopanza好的我刚刚注意到 – 2013-04-07 16:00:56

回答

4

您不能通过更改其参数来覆盖虚拟成员函数。即,Derived::g(int)而不是重写Base::g()

想象一下,你是编译器。你看到函数调用bp->g(1),你知道bp是一个Base*。因此,您可以使用Base来查找名为g的函数,该函数的参数为​​int。你有什么发现?没有!没有一个。

只有当在基类中发现一个函数是虚拟的,它才会考虑对象的动态类型。所以让我们考虑拨打bp->f()。它知道bpBase*,因此它查找Base的成员函数f,它不带任何参数。当然,它发现Base::f(),并认为它是虚拟的。由于它是虚拟的,因此它会在对象的动态类型中查找相同的函数,即Derived。它找到Derived::f()并调用那个。

+0

谢谢!我真的很喜欢你解释这个的方式。十分清晰! – 2013-04-07 16:18:23

+0

@WeizhouSun那么别忘了接受! – 2013-04-07 16:30:12

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 f()的函数,并在Derived中覆盖f(),因此当调用bp-> f()时,派生版本将通过vtable调用。但是Base中没有void g(int),因此bp-> g(1)会导致编译时错误。