2012-06-20 55 views
0

我讀了這麼多的博客,我明白如何在C++中使用虛函數。但是,我仍然不明白爲什麼我們使用虛擬功能。你能給我一個真實世界的例子,以便我可以更容易地看到虛擬功能的實際含義。在c + +的虛擬功能的概念?

+0

你有其他的oop背景嗎? –

+0

是的,我知道java的基本概念。 – devsda

+0

他們實際上在維基上給出了一個例子http://en.wikipedia.org/wiki/Virtual_function – trumpetlicks

回答

1

需要注意的一件重要的事情是,繼承(虛擬關鍵字是基本的)不應該僅用於代碼重用的唯一目的,請使用委託。

授權將是當我們有一個類說寬帶連接與一個方法稱爲連接()。然後你的經理說我們要添加加密,所以你創建了一個類BroadbandConnectionWithEncryption。你的自然本能可能是使用繼承,然後使新類BroadbandConnectionWithEncryption從寬帶連接派生。

缺點是初始類的創建者並沒有將其設計爲繼承,因此您需要更改其定義以使方法connection()爲虛擬,以便可以在派生類中重寫它的行爲。這並不總是理想的。更好的辦法是在這裏使用委託來實現代碼重用。

class BroadBandConnection 
{ 
public: 
    void Connection (string password) 
    { 
     //connection code. 
    } 
}; 

class BroadBandConnectionWithEndcryption 
{ 
public: 
    void Connection (string password) 
    { 
     mbroadbandconnection.Connection(password); 
     //now do some stuff to zero the memory or 
     //do some encryption stuff 
    } 

private: 
    BroadBandConnection mbroadbandconnection; 
}; 

虛擬關鍵字用於多態性的目的。顧名思義,它是一個對象擁有多個表單的能力。這種決定將在設計接口或類時進行。

class IShape 
{ 
    virtual void Draw() = 0; 
}; 

class Square 
{ 
    void Draw() 
    { 
     //draw square on screen 
    } 
}; 

class Circle 
{ 
    void Draw() 
    { 
     //draw circle on screen 
    } 
}; 

我做的draw()的純虛有,我可以離開了這一點,並增加了一些默認實現= 0。純虛擬對於沒有合理的默認實現的接口是有意義的。

這讓我做的事情就是將Shape對象傳遞給各種方法,而且他們不需要關心我剛給他們的東西。他們所知道的是,我必須提供一些支持形狀繪製能力的東西。

IShape* circle = new Circle(); 
IShape* square = new Square(); 

void SomeMethod (IShape* someShape) 
{ 
    someShape->Draw(); //This will call the correct functionality of draw 
} 

今後隨着人們開始新的形狀的思維,他們可以從IShape的推導而只要他們實施得出了一些功能。他們可以將這個對象傳遞給SomeMethod。

0

我們有一個基類(動物)有方法,可以由它的孩子不同地實現(說)。當我們聲明這個方法是虛擬的時,我們可以根據這個方法來實現,並且它會從它的孩子的定義中實現。如果您在孩子的重載方法中使用了地址,則不必使用虛擬方法,但是當您按照父母的方法使用時,您必須使用虛擬方法。

例如,如果你有一個動物的載體,每個人都是不同的。你聲明方法(比如說)是虛擬的,並從動物類中調用它,它將從相應的孩子中調用。

糾正我,如果我錯了,那就是我的理解。

1

首先,this

現在,一個真實的例子。我有一個帶有三個選項卡的GUI程序。每個選項卡都是從共同基礎TabBase派生的類的對象。它有一個虛函數OnActivate()。當選項卡被激活時,調度員在當前選項卡上調用它。有一些常見操作,並且有一些特定於此選項卡的操作。這是通過虛擬功能實現的。

好處是控制器不需要知道它是什麼類型的選項卡。它存儲一個TabBase指針數組,並在它們上調用OnActivate()。虛函數的魔力確保了正確的覆蓋被調用。

class TabBase 
{ 
    virtual void OnActivate() 
    { 
    //Do something... 
    } 
}; 

class SearchTab: public TabBase 
{ 
    void OnActivate() //An override 
    { 
     TabBase::OnActivate(); //Still need the basic setup 
     //And then set up the things that are specific to the search tab 
    } 
} 
+0

爲什麼你會爲此使用繼承?爲什麼Tab類沒有'Activate' *事件*和一個特定的實例'searchTab',會有一個綁定的事件處理程序。似乎動物的例子更好地展示了虛擬方法,而不同標籤的概念是授權的一個很好的例子。 –

+0

C++中沒有內置的事件概念。滾動你自己是可能的,但相當笨拙。 –

0

他們實際上維基

使用動物舉一個例子

http://en.wikipedia.org/wiki/Virtual_function

。動物是超級類,所有動物吃(超類的虛擬功能)。每隻動物的食用方式可能與所有其他動物不同(超越虛擬功能)。我有一個任意動物的列表,當我調用吃飯功能時,他們會顯示他們自己不同的飲食習慣。

0

如果您熟悉Java - 那應該很容易。在Java中,所有類的方法都是有效的虛擬。如果您在派生類中重寫它,並且通過基類引用來調用它,則將調用覆蓋,而不是基礎。

這不是C++中的默認行爲。如果你想要一個函數以這種方式行事,你必須在基類中聲明它是虛擬的。很簡單。

Java充滿了虛擬功能。它只是沒有明確的關鍵字。

0

虛擬功能的目的是實現dynamic dispatch

你說你是熟悉Java,所以那麼對於現實世界使用虛函數,認爲在Java中的任何地方,你會使用interface或者公共/保護方法使用@Override的。

0

使用虛擬功能的決定是一件簡單的事情。你只需要知道什麼時候你想重寫一個基本方法。以下面的代碼爲例:

class animal 
{ 
    public: 
void sound() 
{ 
    cout << "nothing"; 
} 
}; 
class bird : public animal 
{ 
public: 
void sound() 
{ 
cout << "tweet"; 
} 

};

在這種情況下,我想重寫bird()。但如果我沒有?這是會發生什麼:

animal * a = new bird; 
a->sound(); 
**Output** 
nothing 

屏幕會說什麼,因爲所有意圖和目的,C++只看到一個動物。然而,如果你聲明它是虛擬的,它知道要在類層次中搜索最低的方法。再試一次:

class animal{ 
    public: 
    virtual void sound(){cout<<"nothing";} 
    }; 
class bird : public animal 
{ 
    public: 
    void sound() 
    { 
     cout << "tweet"; 
    } 
    }; 
    animal * a = new bird; 
    a->sound(); 
**Output** 
    tweet. 

希望這會有所幫助。

+0

使用單個字母作爲跳過重寫的方法被調用的字母的類名是令人困惑的。 C是一個不同的B?爲什麼不是一個簡單的B是帶有重寫doSomething()方法的A? –

+0

@Doug我編輯了它。現在我相信,這將清楚你。謝謝 – vijay

+0

太棒了!我編輯我的downvote。 –