C++基礎知識 基類指針、虛函數、多態性、純虛函數、虛析構
一、基類指針、派生類指針
父類指針可以new一個子類對象
二、虛函數
有沒有一個解決方法,使我們只定義一個對象指針,就可以調用父類,以及各個子類的同名函數?
有解決方案,這個對象指針必須是一個父類類型,我們如果想通過一個父類指針調用父類、子類中的同名函數的話,這個函數是有要求的;
在父類中,eat函數聲明之前必須要加virtual聲明eat()函數為虛函數。
一旦某個函數被聲明為虛函數,那麽所有派生類(子類)中eat()函數都是虛函數。
為了避免你在子類中寫錯虛函數,在C++11中,你可以在函數聲明中增加一個override關鍵字,這個關鍵字用在子類中,而且是虛函數專用。
override就是用來說明派生類中的虛函數,你用了這個關鍵字之後,編譯器就會認為你這個
final也是虛函數專用,用在父類中,如果我們在父類的函數聲明中加了final,那麽任何嘗試覆蓋在函數的操作都會引發錯誤。
調用虛函數執行的是“動態綁定”。動態表示我們程序運行的時候才能知道調用了那個子類的中的eat()虛函數。
動態的綁定到Men上去,還是Women上去,取決於new的Men還是Women;
動態綁定:運行的時候才決定你的
三、多態性
多態性只是針對虛函數來說的;
多態性:體現在具有繼承關系的父類和子類之間,子類重新定義(重寫)父類的成員函數eat(),同時父類把這個eat()函數聲明為virtual虛函數;
通過父類的指針,只有到了程序運行時期,找到動態綁定到父類指針上的對象,這個對象有可能是某個子類對象,也可能是父類對象;
然後系統內部實際上是要查找一個虛函數表,找到函數eat()的入口地址,從而調用父類或子類的eat()函數,這就是運行時的多態性。
四、純虛函數
純虛函數是在基類中聲明的函數,但是他在基類中沒有定義,但是要求任何派生類都要定義該虛函數自己的實現方法;
基類中實現純虛函數的方法使在函數原型後面增加 =0;
一旦一個類中又純虛函數,那麽你就不能生成這個類的對象了;
抽象類不能用來生成對象,主要目的是用來同意管理子類對象;
(1)純虛函數的類叫做抽象類,不能用來生成該類對象,主要用於當做基類來生成子類用的;
(2)子類必須要實現該基類中定義純虛函數;
五、基類的析構函數一般寫成虛函數(虛析構函數)
用基類指針new子類的對象,在delete的時候,系統不會調用派生類的析構函數,存在問題;
解決方案:將基類的析構函數聲明為虛析構函數;
在public繼承中,基類對派生類及其對象的操作,只能影響那些從基類繼承下來的成員,如果想要用基類對非繼承的成員進行操作,則要把基類的這個函數定義為虛函數,析構函數也為虛函數,基類中的析構函數的虛屬性也會被派生類繼承,即派生類的析構函數也為虛函數。
Human這個類中的析構函數就要聲明為virtual的,也就是說C++11中為了獲得運行時多態,所調用的成員必須是virtual的。
如果一個類想要做基類,我們必須將類的析構函數聲明為virtual虛函數;
只要基類中的析構函數為虛函數,就能保證我們delete基類指針時能夠運行正確,不會出現內存泄漏。
虛函數會增加內存開銷,類裏面定義虛函數,編譯器就會給這個類增加虛函數表,在這個表裏存放虛函數的指針。
本節案例:
// Human.h // 頭文件防衛式聲明 #ifndef __HUMAN__ #define __HUMAN__ #include "stdafx.h" class Human { public: Human(); virtual ~Human(); public: virtual void eat(); virtual void eat2() = 0; }; #endif // Human.cpp #include "stdafx.h" #include "Human.h" #include <iostream> Human::Human() { std::cout << "調用了Human::Human()" << std::endl; } void Human::eat() { std::cout << "人類喜歡吃各種美食" << std::endl; } Human::~Human() { std::cout << "調用了Human::~Human()" << std::endl; } // Men.h #ifndef __MEN__ #define __MEN__ #include "stdafx.h" #include "Human.h" class Men : public Human { public: Men(); ~Men(); public: virtual void eat() override; virtual void eat2(); }; #endif // Men.cpp #include "stdafx.h" #include "Men.h" #include <iostream> void Men::eat() { std::cout << "男人喜歡吃米飯" << std::endl; } void Men::eat2() { std::cout << "男人喜歡吃米飯2" << std::endl; } Men::Men() { std::cout << "調用了Men::Men()" << std::endl; } Men::~Men() { std::cout << "調用了Men::~Men()" << std::endl; } // Women.h #ifndef __WOMEN__ #define __WOMEN__ #include "stdafx.h" #include "Human.h" class Women : public Human { public: Women(); ~Women(); public: virtual void eat() override; virtual void eat2() override; }; #endif // Women.cpp #include "stdafx.h" #include "Women.h" #include <iostream> Women::Women() { std::cout << "調用了Women::Women()" << std::endl; } Women::~Women() { std::cout << "調用了Women::~Women()" << std::endl; } void Women::eat() { std::cout << "女人喜歡吃面食" << std::endl; } void Women::eat2() { std::cout << "女人喜歡吃面食2" << std::endl; } // main.cpp // Project3.cpp : 定義控制臺應用程序的入口點。 // #include "stdafx.h" #include <iostream> #include "Human.h" #include "Men.h" #include "Women.h" using namespace std; int main() { Human *phuman = new Men; phuman->eat(); // 男人喜歡吃米飯 delete phuman; phuman = new Women; phuman->eat(); // 女人喜歡吃面食 delete phuman; //phuman = new Human; //phuman->eat(); // 人類喜歡吃各種美食 //delete phuman; phuman = new Men; phuman->eat2(); // 男人喜歡吃米飯 delete phuman; phuman = new Women; phuman->eat2(); // 女人喜歡吃面食 delete phuman; //Men men; Men *pmen = new Men; delete pmen; Human *phuman1 = new Men; delete phuman1; // 沒有執行子類的析構函數 return 0; }
C++基礎知識 基類指針、虛函數、多態性、純虛函數、虛析構