多型是c++中很關鍵的一部分,在物件導向程式設計中的作用尤為突出,其含義是具有多種形式或形態的情形,簡單來說,多型:向不同物件傳送同乙個訊息,不同的物件在接收時會產生不同的行為。即用乙個函式名可以呼叫不同內容的函式。
多型可分為靜態多型與動態多型,靜態多型的實現在於靜態聯編,關聯出現在編譯階段而非執行期,用物件名或者類名來限定要呼叫的函式,稱為靜態關聯或靜態聯編。常見有三種方法
(1)函式多型(函式與運算子的過載);
(2)巨集多型;
(3)模板多型。
而對於動態多型的實現是執行階段把虛函式和類物件繫結在一起的,即動態聯編,動態繫結。具體的說,通過乙個指向基類的指標呼叫虛成員函式的時候,執行時系統將能夠根據指標所指向的實際物件呼叫恰當的成員函式實現。
當編譯器使用動態繫結時,就會在執行時再去確定物件的型別以及正確的呼叫函式。而要讓編譯器採用遲繫結,就要在基類中宣告函式時使用virtual關鍵字,這樣的函式稱之為虛函式(virtual functions)。根據賦值相容,用基類型別的指標指向派生類,就可以通過這個指標來使用派生類的成員函式。如果這個函式是普通的成員函式,通過基類型別的指標訪問到的只能是基類的同名成員。 而如果將它設定為虛函式,則可以使用基類型別的指標訪問到指標正在指向的派生類的同名函式。這樣,通過基類型別的指標,就可以使屬於不同派生類的不同物件產生不同的行為,從而實現執行過程的多型。可看這個例子:
#include using namespace std;class a
此時輸出a::print ,若將a類中的print( )函式宣告為virtual,則此時就為動態聯編 程式執行結果為: b::print。
注意點1:建構函式和靜態成員函式不能是虛函式:靜態成員函式不能為虛函式,是因為virtual函式由編譯器提供了this指標,而靜態成員函式沒有this指標,是不受限制於某個物件;建構函式不能為虛函式,是因為構造的時候,物件還是一片未定型的空間,只有構造完成後,物件才是具體類的例項。
class a; //error
};class b
; //error 「virtual」不能和「static」一起使用
};int main( )
注意點2:派生類物件的指標可以直接賦值給基類指標,如上面中的a *a=&b;*a可以看作乙個類a的物件,訪問它的public成員。通過強制指標型別轉換,可以把a轉換成b類的指標: a = &b; aa = static_cast< b * > a。此外指向基類的指標,可以指向它的公有派生的物件,但不能指向私有派生的物件,對於引用也是一樣的。
class b
注意點3:建構函式中呼叫virtual函式 ,在建構函式和析構函式中呼叫虛函式時:他們呼叫的函式是自己的類或基類中定義的函式,不會等到執行時才決定呼叫自己的還是派生類的函式。
class transactionvirtual void logtransaction( ) = 0;
};class buytransaction: public transaction
};class selltransaction: public transaction
};int main( )
以上**應該會有報錯提示,
若將基類的transaction中虛函式logtransaction改為:
virtual void logtransaction( )void virtual func2( )
};class derived:public base
};int main( )
因為,base類的func1( )為非靜態成員函式,編譯器會給加乙個this指標: 相當於 void func1( ) 編譯這個函式的**的時候,由於func2( )是虛函式,this是基類指標,所以是動態聯編。上面這個程式執行到func1函式中時, this指標指向的是d,所以經過動態聯編,呼叫的是derived::func2( )。
注意點5:虛函式的訪問許可權,如果基類定義的成員虛函式是私有的,我們來看看會怎麼樣
class base};class derived : public base
};int main( )
對於類的private成員 ,只能由該類中的函式、其友元函式訪問,不能被任何其他訪問,該類的物件也不能訪問.所以即使是虛函式,也沒辦法訪問。但是!派生類虛函式的可訪問性與繼承的方式和虛函式在基類的宣告方式有關(public,或private)與派生類宣告的方式無關(如public繼承,但宣告為private,但仍可訪問),把上面的public與private互換位置,程式可以正常執行,並輸出
derived:func( )。
注意點6:虛函式與友元,先看**
class a;
class b
{private:
int x;
void print() { cout《程式執行結果為:99 99
由第乙個99可知,a是b的友元類,a中的所有成員函式都為b的友元函式,可訪問b的私有成員函式。友元類a不是基類b的一部分,更不是派生類d的一部分。從上例看,友元視乎能夠被繼承,基類的友元函式或友元類能夠訪問派生類的私有成員。但public繼承是一種「is a」的關係,即乙個派生類物件可看成乙個基類物件。所以,上例中不是基類的友元被繼承了,而是派生類被識別為基類了。而第二個99說明乙個友元類的派生類,可以通過其基類介面去訪問設定其基類為友元類的類的私有成員,也就是說乙個類的友元類的派生類,某種意義上還是其友元類。
注意點7:析構函式通常是虛函式。虛析構函式保證了在析構時,避免只呼叫基類析構函式而不呼叫派生類析構函式的情況,保證資源正常釋放,避免了記憶體釋放。只有當乙個類被用來作為基類的時候,才會把析構函式寫成虛函式。
以上為個人總結,有不妥的地方歡迎指出。
C 中 虛函式及包含多型的實現
我們分三個方面來說明虛函式以及用虛函式實現的包含多型。第乙個 什麼是虛函式?從語法上來說虛函式就是用 virtual 宣告的函式。所以定義乙個虛函式很簡單。重點是你需要知道我們如何用虛函式解決實際的問題。第二個 編譯器是如何解析函式呼叫語句的?通常我們是用乙個型別定義乙個物件,或者 new乙個物件,...
C 中虛函式與多型
物件導向理論中的3個術語 物件 方法和訊息。物件 object 不言而喻,它是構成系統的基本單位,有屬性和行為兩個要素,在c 中,每個物件都是由資料和函式這兩部分組成的,資料即是物件的屬性,行為稱之為方法 method 方法是對資料的操作,通常由函式實現。呼叫物件中的函式就是向該物件傳送乙個訊息 m...
C 中虛函式和多型
1.c 中的虛函式 c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtt...