多態(靜態多態+動態多態) 多態是面向對象的三大特征(封裝,繼承,多態)之一。 教科書定義:指相同對象接收不同消息或不同對象接到相同消息產生不同的動作。簡單來說就是當發出一條命令時,不同的對象接收到同樣的命令時,所做出的動作是不同的。
靜態多態(早綁定) 如下代碼,兩個一樣的函數名,但是參數不同,在調用時,程序會根據參數不同調用不同函數。因為程序很早就把這種情況編譯進去,這就情況就叫靜態多態。
class Rect{public: int calcArea(int width); int calcArea(int width, int height);};int main(){ Rect rect; rect.calcArea(10); rect.calcArea(10, 20); return 0;}動態多態(晚綁定) 動態多態必須以封裝和繼承為基礎,動態多態起碼要有兩個類,一個是子類,一個是父類,當然也可以有三個類,只有有三個類的時候我們的動態多態才能表現的比較明顯,以下代碼為例
class Circle :public Shape{public: Circle(double r); double calcArea();PRivate: double m_dR;};double Circle::calArea(){ return 3.14*m_dR*m_dR;};double Rect::calcArea(){ return m_dWidth*m_dHeight;};int main(){ Shape *shape1 = new Circle(4,.0); Shape *shape2 = new Rect(3.0,5.0); shape1->calcArea();//用到的都是父類的計算面積,屏幕上會打印出claArea() shape2->calcArea(); //.... return 0;}可以利用virtual虛函數來實現多態。如下代碼,輸出的就是計算的圓的面積
class Shape{public: virtual double calcArea()//虛函數 { cout << "clacArea" << endl; return 0; }};class Circle :public Shape{public: Circle(double r); virtual double calcArea();//virtual不是必須,系統會自動加一個virtualprivate: double m_dR;};但是動態多態容易引起內存泄漏的問題,如下代碼 代碼1:
class Shape{public: Shape(); virtual double calcArea();};class Circle :public Shape{public: Circle(int x, int y, double r); ~Circle(); virtual double calcArea();private: double m_dR; Coordinate *m_pCenter; //多定義了一個指針的數據成員};Circle::Circle(int x, int y, double r){ m_pCenter = new Coordinate(x, y); m_dR = r;}Circle::~Circle{ delete m_pCenter; m_pCenter = NULL;}int main(){ Shape *shape1 = new Circle(3, 5, 4.0); shape1->calArea(); delete shape1;//想借助父類的指針去銷毀子類的指針時,會出問題,只執行父類的析構 shape1 = NULL; return 0;}如上代碼,我們在Circle中多定義了一個成員指針*m_pCenter,當我們在main()函數中delete shape1時,由于它是父類的指針,銷毀時他只會調用父類的析構函數,而不會調用子類的析構函數,這就造成了內存的泄漏。這時我們要引入虛析構函數,同樣是用virtual關鍵字修飾析構函數。代碼示例如下: 代碼1.1
class Shape{public: Shape(); virtual ~shape();//虛析構函數 virtual double calcArea();};class Circle :public Shape{public: Circle(int x, int y, double r); virtual ~Circle(); virtual double calcArea();private: double m_dR; Coordinate *m_pCenter; //多定義了一個指針的數據成員};這個時候我們再用代碼1中的main()函數,這個時候我們再使用delete,如果我們這個時候在delete后面跟上父類指針的時候,父類指針指向的是哪個對象,那么哪個對象的析構函數就先得以執行,然后再執行父類的。這樣就保證了內存不會泄漏。
同樣vitual的使用也有一些限制 1.普通函數(全局函數)不能是虛函數,要是類中的成員函數。 2.靜態成員函數不能是虛函數 3.內聯函數不能是虛函數 4.構造函數不能是虛函數
虛函數的實現原理 先介紹一下函數指針:之前我們知道如果通過指針指向對象,我們叫他對象指針,那么指針當然也可以指向函數,函數的本質是一段二進制代碼,它寫在內存當中,我們可以通過指針來指向這段代碼的開頭,那么計算機就會從開頭一直執行,直到函數的結尾,然后再返回。函數的指針和普通的指針本質上時一樣的,如下圖
我們看如上的代碼,此時的虛函數如何實現呢?(等我搞懂了再說—–
新聞熱點
疑難解答
圖片精選