2010-04-04 61 views
3

下面的代碼,打印出C++多態性與切片

Derived 
Base 
Base 

但我需要投入每一個用戶派生對象::項,調用它自己的打印功能,而不是基類之一。我可以實現,而不使用指針?如果不可能,我應該如何編寫一個接一個地刪除User :: items的函數並釋放內存,以避免內存泄漏?

#include <iostream> 
#include <vector> 
#include <algorithm> 

using namespace std; 

class Base{ 
public: 
    virtual void print(){ cout << "Base" << endl;} 
}; 

class Derived: public Base{ 
public: 
    void print(){ cout << "Derived" << endl;} 
}; 

class User{ 
public: 
    vector<Base> items; 
    void add_item(Base& item){ 
    item.print(); 
    items.push_back(item); 
    items.back().print(); 
    } 
}; 

void fill_items(User& u){ 
    Derived d; 
    u.add_item(d); 
} 

int main(){ 
    User u; 
    fill_items(u); 
    u.items[0].print(); 
} 
+2

使用智能指針來避免內存泄漏 – 2010-04-04 17:44:28

回答

5

你需要使用指針,你需要給你的基類一個虛析構函數。析構函數不需要做任何事情,但它必須存在。您的添加功能看起來像:

void add_item(Base * item){ 
    item->print(); 
    items.push_back(item); 
} 

其中項目是vector<Base *>。摧毀項目(假設虛析構函數):

for(int i = 0; i < items.size(); i++) { 
    delete items[i]; 
} 
items.clear(); 
+0

@Neil虛擬析構函數是否應該存在以使其虛擬?那麼它會動態地銷燬基類和派生類對象? – 2010-04-05 06:42:59

+0

@Draco析構函數需要被創建並定義爲虛擬的,這樣當通過基類指針刪除對象時,銷燬將遵循虛函數查找機制。析構函數會自動「鏈接」從一個孩子到另一個孩子,但是你必須讓孩子在第一個地方打電話! – 2010-04-06 01:29:51

+0

換句話說,對於一個非虛擬的dtor,「刪除項目[i];」將只調用基本析構函數而不是「實際派生」的析構函數。添加'虛擬'使得正確的功能得到查找和調用。 (您只需要基類析構函數上的虛擬標記,btw,並且您不一定需要派生類的顯式析構函數。) – 2010-04-06 01:32:51

1

您需要爲基礎,使Derived類型的肯定對象虛析構函數調用刪除Base類型的指針時得到適當的破壞。

class Base{ 
public: 
    virtual void print(){ cout << "Base" << endl;} 

    virtual ~Base() { } // virtual destructor 
}; 

然後你可以使用提升ptr_vector的指針存儲到你的對象當容器被摧毀被刪除。

+1

它不防止內存泄漏,它可以防止未定義的行爲。 – 2010-04-04 17:50:36

+0

沒錯。添加了關於這一點的小費。 – 2010-04-04 17:51:21

+0

恩,不,你沒有。 – 2010-04-04 17:54:10

0

只是解釋:

爲了理解正在發生的事情,你可能會嘗試定義類的抽象基(例如定義的任何方法,純虛)。在這種情況下,我希望你會看到編譯器錯誤。 通過這種方式,您可以識別矢量實際執行的操作:它在push_back(派生)時通過複製構造方式創建類Base的新實例。 這就是爲什麼你想用指針代替。然後,vector將與最初創建的Derived類型對象(而不是Base類型的自己的副本)一起工作。

+0

是的,我知道。這就是所謂的切片。我只是想知道除了使用指針之外是否還有其他的機會。 – 2010-04-08 09:44:29