2013-06-28 26 views
3

我知道關鍵字virtual使得基類的多態,如果我創建一個對象,並調用virtual function,相應的功能將根據運行時間分配來調用,但我爲什麼要創建不同類型的對象。我的意思是使基類具有多態性?

Base *ptr = new Derived; 

ptr->virtualfunction(); //calls the function which has implemented in Derived class. 

如果我創建一個對象,以便

Derived *ptr = new Derived; 
ptr->virtualfunction(); // which does the same without the need of making the function virtual. 
+3

這裏檢查例如:http://www.cplusplus.com/doc/tutorial/polymorphism/如果你需要這些對象的集合,或者你不知道對象的確切亞型(因爲它取決於配置,用戶輸入等),你需要多態。 –

+0

所以你的問題是爲什麼需要虛擬方法呢? – Inspired

+1

_「但我爲什麼要創建不同類型的對象」 _無論你的例子創建同一類型的對象,不同的是,你用它來指代它指針的類型,但是這兩個例子中創建一個'Derived'。 –

回答

8

因爲你可能希望存儲不同類型在一起對象:

std::vector<std::unique_ptr<Base>> v; 

v.push_back(make_unique(new DerivedA())); 
v.push_back(make_unique(new DerivedB())); 
v.push_back(make_unique(new DerivedC())); 

現在,如果你去了這vector

for (auto& p : v) { 
    p->foo(); 
} 

它將調用DerivedA,B,和C的適當foo()

+2

你應該補充說'std :: make_unique'將從C++ 14開始可用。此外,調用它的真正異常安全的方法是'的std :: make_unique ()'和'不是的std :: make_unique(新富())'。讀到這裏爲什麼:http://www.gotw.ca/gotw/056.htm –

+0

,只是加入到本 - 多態性是要付出代價的,這個代價是虛擬方法表(或虛函數表)來存儲方法指針。使用虛擬關鍵字告訴編譯器的方式:「我想多態的,我接受這個將耗資什麼」 –

+0

@PaulManta這正是我爲什麼不能以'std'前綴它。至少在目前的標準下,'make_unique'是某種慣用的拼寫方法,我用它來縮短這個例子。無論如何,你對C++ 14的見解都很好。 –

2

讓我們用一個簡單的例子:假設你有

class Base {}; 
class Derived1 : public Base {}; 
class Derived2 : public Base {}; 

現在,讓我們說你要能夠在一個載體(或容器)都Derived1和Derived2的實例存儲。 在這種情況下,您必須使用基類。

std::vector<Base*> 
// or std::vector<std::unique_ptr<Base>> 
1

的必要性多態性是在以相同的方式處理不同的數據的需要。對於具有不同形狀的數據集重複實施相同的算法,並不是簡單地只有一個算法的實現,並用不同的運算符對其進行參數化?

這是多態的本質。您從算法開始,建立它必須與之交互的接口,然後構建該接口的實現。在C++中,接口的概念隱含在每個類中。任何類都暴露一個接口(儘管它可以通過它的祖先支持許多接口),並且它的後代也實現它。通過使某些方法變爲虛擬,後代可以覆蓋並使它們適應它們自己的內部結構,而不用修改從外部操縱對象的方式。

所以多態性是真的,它可以採用不同的形狀和手段來訪問和uniformally操縱它們的值。回答你的問題的關鍵點可能是算法不知道它正在操作的實施方法。您提供了一個簡單的示例,其中代碼知道它可以與Derived的實例一起使用,因此可以直接調用它的方法。在通用代碼或代碼中引用一個接口(可以這麼說),這種知識不存在,這迫使代碼依賴基類方法(並且要求程序員確保他計劃使用的代碼類定義明確 - 即虛擬 - 在需要的地方)。

有多態性的許多有用的應用,但它們都從上述原理導出:

  • 異質數據集(由其他答案所示),
  • injection(其中相同的接口的不同實現可以在運行時交換一個)
  • 測試(更具體地說是模擬,其中與給定類C交互的類被替換爲幫助測試C的正確行爲的假人),

僅舉幾例。請注意,編譯時多態性(模板)和運行時多態性(方法和繼承)都實現了該目標,儘管方式不同,並且具有不同的優缺點。