日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++_虚继承_虚函数_纯虚函数(多继承的二义性,多态)

發布時間:2024/7/5 c/c++ 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++_虚继承_虚函数_纯虚函数(多继承的二义性,多态) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基本信息

每一個類都有一個虛表,以及虛表指針; 虛表的內容是編譯器決定的,虛表中用于存放虛函數的指針, 程序運行時的類型信息等;
每個多態對象都存放著一個指向當前類型的虛表的指針, 該指針在構造函數中被賦值, 一般來說當調用當前這個類的構造函數, 則虛表指針就指向當前類的虛表

虛繼承

用于解決多重繼承的過程中成員訪問的二義性(菱形繼承)
格式:class 類名 : virtual 繼承方式 基類類名
注:在虛繼承的過程中,編譯器會為子類創建一個虛表,以及一個虛基表指針(占用對象空間)指向虛表(不占用對象空間)
例:

#include<iostream> using namespace std; class A{private:int a;public:A(){cout<<"A()"<<endl;}~A(){cout<<"~A()"<<endl;} }; class B:virtual public A{private:int b;public:B(){cout<<"B()"<<endl;}~B(){cout<<"~B()"<<endl;} }; class C:virtual public A{private:int c;public:C(){cout<<"C()"<<endl;}~C(){cout<<"~C()"<<endl;} }; class D:public B,public C{private:int d;public:D(){cout<<"D()"<<endl;}~D(){cout<<"~D()"<<endl;} }; int main(){//64位虛表指針為8個字節 cout<<sizeof(A)<<endl; //輸出4 cout<<sizeof(B)<<endl;//輸出 B本身(4)+A(4)+虛表指針(8)=16 cout<<sizeof(C)<<endl;//輸出與B相同 cout<<sizeof(D)<<endl;//輸出 B+C+D本身-A(一份的A)=32

上述代碼中: B, C虛繼承于A, 他們二者”共享”一份A(用集合的方式理解,A屬于B, C的交集), 當D繼承B,C的時候只會保留一份A在D中
若未采用虛繼承在D創建對象的時候,會創建2份的A,出現冗余, 使用虛繼承繼承基類的兩個虛指針,并調整虛指針與虛基類首地址的偏移量,使得繼承過程中只保留一份的A
當使用虛繼承的過程中,虛基類被共享,無論繼承多少次,虛表指針都只會指向一份的虛基類,對象模型中只會存有一份的虛基類對象

虛函數

在基類中使用virtual修飾的成員函數,當函數聲明為虛函數時,告訴編譯器不要靜態鏈接到該函數,而是根據程序的運行過程中動態地根據該對象類型來調用函數, 就所謂的多態
注:當基類成員函數聲明為virtual, 子類進行對virtual重寫,那么重寫后的函數都為虛函數(即使該函數前面沒寫virtual關鍵字); 虛函數成員的virtual關鍵字只能出現在類中定義的函數原型前面, 不能出現在類外成員函數實現的前面
虛函數一般不聲明為inline函數, inline函數屬于靜態綁定, 而虛函數的調用是動態綁定, 如果將虛函數作為inline函數也不會出錯
構造函數, 靜態函數, 復制構造函數不可做為虛函數, 原因只在于虛函數為動態綁定;

#include <iostream> using namespace std; class Shape {protected:int width, height;public:Shape( int a=0, int b=0){width = a;height = b;}virtual int area(){//編譯時,生成一個虛表以及虛表指針cout << "Parent class area :" <<endl;return 0;} }; class Rectangle: public Shape{public:Rectangle( int a=0, int b=0):Shape(a, b) { }virtual int area () {//為虛函數,即使沒有關鍵字virtualcout << "Rectangle class area :" <<endl;return (width * height); } }; class Triangle: public Shape{public:Triangle( int a=0, int b=0):Shape(a, b) { }virtual int area (){cout << "Triangle class area :" <<endl;return (width * height / 2); } }; int main( ) {Shape *shape;Rectangle rec(10,7);Triangle tri(10,5);shape = &rec;shape->area(); // 調用矩形的求面積函數 areashape = &tri;// 存儲三角形的地址shape->area(); // 調用三角形的求面積函數 areareturn 0; }

此時,編譯器看的是指針的內容(決定了能夠調用哪些虛函數),它指向的對象類型決定了該調用誰的虛函數。因此,由于 tri 和 rec 類的對象的地址存儲在 *shape 中,所以會調用各自的 area() 函數。

動態綁定的底層實現:
虛表指針需要初始化才能調用虛函數,虛表指針在構造對象的時候初始化(初始化順序與構造函數的調用順序一致),當構造函數發現BASE具有虛函數,虛指針指向BASE的虛表中的虛函數,當執行構造子類對象的時候,子類中虛指針指向子類虛表中的虛函數;當對象創建好后,虛表指針指向的是子類的虛函數,從而對象調用虛函數時,實現多態

注:虛表會被繼承,當子類重寫虛函數的時候,那么虛表中的虛函數地址則會改變
在動態分配內存的時候,析構函數必須是虛函數(利用動態綁定)防止不會調用所需的析構函數
使用虛函數意味著多態,多態必須具備的三個條件:繼承關系; 繼承的過程中必須有同名的虛函數; 存在基類的指針或引用,通過該指針或引用調用虛函數

虛析構函數
析構函數可作為虛函數, 方便父類指針知道該調用哪個子類的析構函數(析構函數的多態)
一般情況下, 如果涉及到多態, 則將析構函數設置為virtual

#include<iostream> using namespace std; class BASE{public:~BASE(){cout<<"父類析構函數"<<endl;} }; class Derive:public BASE{public:Derive(){} ~Derive(){cout<<"子類析構函數"<<endl;} }; int main(){BASE *b=new Derive();delete b;return 0; }

//上述代碼輸出:父類析構函數,由于BASE指針偏移量的問題,未將父類析構函數設置為虛析構函數,導致靜態綁定只會釋放父類內存區,不會釋放子類內存區,導致內存泄漏;
為了避免這種錯誤應將父類,子類的析構函數設置為virtual,則會解決這個問題
注: 子類對象析構函數的調用順序,先調用子類析構函數, 然后調用父類析構函數, 調用順序與構造函數調用順序相反

純虛函數 (抽象類)

在基類重定義純虛函數,以便在派生類中重新定義該函數來適用于對象,純虛函數就相當于接口,用于規范派生類行為
包含純虛函數的類是抽象類,不能實例化, 當子類繼承抽象類時,若沒有實現純虛函數, 則子類還是抽象類
語法: virtual void function()=0;
等于0表示沒有函數體,

class Shape {protected:int width, height;public:Shape( int a=0, int b=0){width = a;height = b;}// pure virtual functionvirtual int area() = 0; };

注: C++中,父類中的純虛函可以有實現方式, 但是編譯器會忽略, 父類依舊為抽象類, 由于抽象類不能實例化, 但是可以定義指針或引用, 通過指針和引用依舊能實現多態, 與Java中抽象類實現多態的方式一致
總結:

  • 虛繼承: 虛表基表, 虛基指針主要用來記錄偏移量(虛基指針在虛基表上),以保證多繼承的過程中只復制一份的基類
  • 虛函數: 虛表,虛指針主要用于指向虛函數(虛指針指向虛表中的虛函數地址)
  • 純虛函數: 就是接口, 規范子類行為

總結

以上是生活随笔為你收集整理的C++_虚继承_虚函数_纯虚函数(多继承的二义性,多态)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。