虛函式和動態繫結 C 學習

2022-07-09 15:48:11 字數 3527 閱讀 1685

1.什麼是虛成員函式

即其宣告在返回型別的前面帶有關鍵字virtual的類成員函式。定義為virtual的函式是基類期待派生類重新定義的,基類希望派生類繼承的函式不能定義為虛函式。

2.動態繫結

通過動態繫結,我們能夠編寫程式使用繼承層次中任意型別的物件,無須關心物件的具體型別。

在c++中,通過基類的引用(或指標)呼叫虛函式時,發生動態繫結引用(或指標)既可以指向基類物件也可以指向派生類物件,這一事實是動態繫結的關鍵

用引用(或指標)呼叫的虛函式在執行時確定,被呼叫的函式是引用(或指標)所指物件的實際型別所定義的。

3.基類成員函式

成員預設為非虛函式,對非虛函式的呼叫在編譯時確定。為了指明函式為虛函式,在其返回型別的前面加上virtual。除建構函式之外,任意非static成員函式都可以是虛函式保留字virtual只在類內部的成員函式中宣告,不能用在類定義體外部出現的函式定義上。

4.派生類與虛函式

儘管不是必須這樣做,派生類一般會重新定義所繼承的虛函式。如果派生類沒有重新定義虛函式,則使用基類中定義的版本。派生型別必須對想要重新定義的每個繼承成員進行宣告。派生類中虛函式的宣告必須與基類中的定義方式一樣,但有乙個例外:返回基型別的引用(或指標)的虛函式。派生類的虛函式可以返回基類函式所返回型別的派生類的引用(或指標)。

注意:一旦函式在基類宣告中為虛函式,它就一直為虛函式,派生類無法改變該函式為虛函式這一事實。派生類重定義虛函式時,可以使用virtual保留字,但不是必須這樣做

5.virtual與其他成員函式

要觸發動態繫結,必須滿足兩個條件:第一,只有指定為虛函式的成員函式才能進行動態繫結,成員函式預設為非虛函式,非虛函式不進行動態繫結;第二,必須通過基類型別的引用或指標進行函式呼叫

1)從派生類到基類的轉換

因為每個派生類物件都包含基類部分,所以可將基類型別的引用繫結到派生類物件的基類部分,也可以將指向基類的指標指向派生類物件。

使用基類型別的指標和引用時,不知道指標和引用所繫結的物件的型別:基類型別的引用或指標既可以引用基類型別物件,又可以引用派生型別物件。無論實際物件是哪一種,編譯器都將它當作基類型別物件。(將派生類物件當作基類物件是安全的,因為每個派生類物件都擁有基類子物件。而且,派生類繼承基類的操作,即任何作用於基類物件上執行的操作也可以通過派生類物件使用)。

注:基類型別引用和指標的關鍵點在於靜態型別和動態型別可能不同。靜態型別,在編譯時可知的引用型別或指標型別;動態型別,指標或引用型別繫結的物件的型別,這僅僅是執行時可知。

2)可以在執行時確定virtual函式的呼叫

c++動態繫結的關鍵:物件的實際型別(動態型別)可能不同於該物件的引用或指標的靜態型別

3)在編譯時確定非virtual函式的呼叫

非虛函式總是在編譯時根據呼叫該函式的物件、引用、指標的型別而確定。

4)覆蓋虛函式機制

在某些情況下,希望覆蓋虛函式機制並強制函式呼叫使用虛函式的特定版本,這是可以使用作用域操作符。

如item_base *basep = &derived; basep->item_base::net_price(42);//該呼叫編譯時確定(如果沒有作用域則在執行時呼叫basep所指向物件相對應的函式)

使用覆蓋虛函式機制的理由是為了派生類虛函式呼叫基類中的版本。這種情況下,基類版本可以完成基礎層次中所有型別的公共任務,而每個派生型別只新增自己的特殊工作。

派生類虛函式呼叫基類版本時,必須顯式使用作用域操作符。如果派生類函式忽略了這樣做,則函式呼叫會在執行時確定並且將會是乙個自身呼叫,從而導致無窮遞迴

例子:基類item_base的定義(item_base.h)

1 #ifndef item_base_h

2 #define item_base_h

3 #include

4 class item_base

7         std::string book() const        /*返回書的編號*/

8         virtual double net_price(std::size_t n) const   /*返回給定數目的某書的總價(實價)*/

9        

12         virtual ~item_base()

13 private:

14         std::string isbn;

15 protected:

16         double price;           /*price為protected,可以被派生類物件訪問但不能被該型別的普通使用者訪問*/

17 };

18 #endif

派生類 bulk_item(bulk_item.h)

1 #ifndef bulk_item_h

2 #define bulk_item_h

3 #include "item_base.h"

4 5 class bulk_item:public item_base

6 11         double net_price(std::size_t n) const;

12 private:

13         std::size_t min_qty;    //折扣的最小購買數量

14         double discount;        //折扣

15 };

16 #endif

派生類實現bulk_item.cpp

1 #include

2 #include "bulk_item.h"

3 using namespace std;

4 5 double bulk_item::net_price(size_t n) const

6 12

13 void print_total(ostream &os, const item_base &item, size_t n)

14 測試test.cpp

1 #include

2 #include "item_base.h"

3 #include "bulk_item.h"

4 using namespace std;

5 6 int main()

7 測試結果:27.6

使用基類item_base的引用呼叫虛成員函式會發生動態繫結,被呼叫的函式是與動態型別即bulk_item相對應的函式。

使用作用域操作符覆蓋虛函式機制,即item_base::可以呼叫基類的版本。

虛函式和動態繫結 C 學習

1.什麼是虛成員函式 即其宣告在返回型別的前面帶有關鍵字virtual的類成員函式。定義為virtual的函式是基類期待派生類重新定義的,基類希望派生類繼承的函式不能定義為虛函式。2.動態繫結 通過動態繫結,我們能夠編寫程式使用繼承層次中任意型別的物件,無須關心物件的具體型別。在c 中,通過基類的引...

c 規避虛函式的動態繫結

如果我們希望明確指定呼叫 基類 還是 子類的虛函式版本。那麼可以通過作用域運算子 注 這一特性是設計模式中 責任鏈模式 的核心實現手段。class a class b public a int tmain int argc,tchar ar 這個特性非常有用,當很多派生類 都用相同動作時,我們可以把...

虛函式與動態繫結

在定義基類時,我們希望基類中的有些函式可以在派生類中重新定義。比如,我們定義了基類記錄的書,可以求出買了多少書花了多少錢 而在派生類中,我們定義的是打折的書,還是要計算買了多少書花了多少錢。這時,就需要重新定義計算錢數的函式了。注意,這裡的重新定義,與之前講過的函式過載或者操作符過載不同 後面兩類,...