2013-04-07 50 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)會導致編譯時錯誤。