2017-02-16 55 views
2

我正在查看虛擬功能行爲的示例情況。鑑於這個測試代碼,我有幾個關於它的行爲的問題。虛擬功能簽名不匹配及其行爲

class A 
{ 
public: 
    A(int x) 
    { 
     cout << "In A Constructor" << endl; 
     print(); 
    } 
    ~A(){ 
     cout << "In A Destructor" << endl; 
     delete _val; 
    } 
    virtual void print() { cout << "A." << endl; } 
private: 
    char* _val; 
}; 

class B: public A 
{ 
public: 
    B(int x, int y) : A(x) 
    { 
     _dVal = new char[y]; 
     cout << "In B Constructor 1" << endl; 
     print(); 
    } 
    B() : A(0) 
    { 
     _dVal = new char[1]; 
     cout << "In B Constructor 2" << endl; 
     print(); 
    } 
    ~B(){ 
     cout << "In B Destructor" << endl; 
     delete _dVal; 
    } 
    void print() { cout << "B" << endl; } 
private: 
    char* _dVal; 
}; 

int main(int argc, char** argv) { 
    A* p1 = new B(); 
    p1->print(); 
    delete p1; 
    return 0; 
} 

的輸出是:

In A Constructor 
A. 
In B Constructor 2 
B 
B 
In A Destructor 

1)爲什麼被稱爲B類打印如果類A是唯一一個表示它作爲一個虛函數和它正被解除引用(稱爲 - > )? 2)如果構造函數實際上被調用,爲什麼B的析構函數永遠不會被調用?

+1

如果函數在基類中是虛擬的,那麼它在所有派生類中也是虛擬的。同樣是析構函數。 –

+1

請問每個問題一個問題。 –

回答

4

1)爲什麼打印要求類B,如果類A是唯一一個表示它是一個虛函數,並且被解引用( - >)調用?

這就是虛擬功能應該做的事情。指針p1的類型爲A*,但實際上它指向的是B類型的對象。而這種動態綁定僅在派生類使用指針或對基類的引用進行處理時纔會發生。

另請注意,派生類中的覆蓋函數也是virtual(無論關鍵字virtual是否在其聲明中使用)。

2)爲什麼如果構造函數實際上被調用,B的析構函數永遠不會被調用?

B析構函數不被調用,因爲你不聲明基類的析構函數(即A::~A)爲virtual destructor。這種情況的行爲是不確定的。 B的構造函數被調用是因爲您構造B明確由new B()

+0

有趣。由於行爲未定義,這是否意味着B類的_dVal會變成oprhan並導致內存泄漏呢? – w0ffen

+0

@ user49096從你觀察到的結果來看,是的。請注意,它是不確定的,任何事情都是可能的。 – songyuanyao

+0

@ user49096「_因爲行爲是不確定的,這是否意味着_」不,它意味着發生的事情沒有被定義,未定義,未知...... – curiousguy