2016-07-25 64 views
-1
#include <iostream> 
using namespace std; 

class Criminal { 
public: 
    virtual void getType() = 0; 
    virtual void getCrime() { cout << "Unknown" << endl; } 
}; 

class Thug : public Criminal { 
public: 
    void getType() { cout << "Thugging" << endl; } 
    void getCrime() { cout << "Gangsterism" << endl; } 
}; 

class Tupac : public Thug { 
public: 
    void getType() { cout << "Rapper" << endl; } 
    void getCrime() { 
     cout << "Being the best rapper to ever live" << endl; 
    } 
}; 

int main() { 
    Criminal* tupac = new Tupac(); 
    Criminal* thug = new Thug(); 
    Thug* poser = new Tupac(); // Thug has no virtual function 
    //Criminal shouldNotCompile; 

    tupac->getType();  
    tupac->getCrime();  

    thug->getType();   
    thug->getCrime();  

    poser->getType();  // I intend to call Thug::getType() 
    poser->getCrime();  // I intend to call Thug::getCrime() 

    delete tupac; 
    delete thug; 
    delete poser; 

    getchar(); 

    return 0; 
} 

輸出是從基指針的C++虛擬類?

Rapper 
Being the best rapper to ever live 
Thugging 
Gangsterism 
Rapper 
Being the best rapper to ever live 

但我打算從暴徒指針波塞爾調用打印「Thugging」和「強盜」。

我該怎麼做?我期望我的代碼按原樣工作,因爲「Thug」函數不是虛擬的,所以Thug *指針調用Thug函數時不應該調用任何東西?

爲什麼我的代碼不能按照我的意圖工作?我的困惑在哪裏?

什麼是簡單的方法來獲得我的預期行爲?

+0

我很困惑。你已經創建了兩個'Tupac'實例 - 你爲什麼期望它們的行爲不同?虛擬成員函數的重點是調用派生最多的類中的重寫。 –

+0

另外,'delete tupac;'和另外兩個'delete'調用表現出未定義的行爲,因爲'Criminal'的析構函數是非虛擬的。 –

+1

*「這個」Thug「函數不是虛擬的」* False。虛擬函數的覆蓋本身是虛擬的,儘管虛擬關鍵字可以省略。 'Thug :: getType()'和'Thug :: getCrime()'實際上是虛擬成員函數。 –

回答

4

virtual成員函數的性質是繼承的。您可能沒有聲明Thug::getType()virtual,但它仍然是因爲Criminal::getType()是。在對象繼承自Criminal的任何類型上調用getType()仍將通過虛擬調度。除非你明確指定getType()你想要的:

poser->getType(); // virtual dispatch, ends up invoking Tupac::getType() 
poser->Thug::getType(); // explicitly call Thug::getType(), no dispatch 

這些電話:

delete tupac; 
delete thug; 
delete poser; 

是危險的,由於Criminal的析構函數不是virtual。你實際上並沒有釋放所有的內存或者摧毀所有的成員。

+0

對,不會刪除tupac調用Criminal析構函數,然後釋放分配給tupac的內存? – Jason

+0

@Jason這會叫'刑事'析構者,是的。但它不會稱爲「Thug」或​​「Tupac」析構函數。 – Barry

+0

@Jason no,析構函數不是虛擬的,所以當你刪除一個犯罪指針時,它會調用犯罪析構函數。 – kfsone