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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

C++基础15-类和对象之多态

發布時間:2025/3/15 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++基础15-类和对象之多态 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

總結:

1、在父類中申明虛函數時,一般情況下在子類中也申明(便于讀代碼)

一、賦值兼容

賦值兼容規則是指在需要基類對象的任何地方都可以使用公有派生類的對象來替代。

賦值兼容是一種默認行為,不需要任何的顯示的轉化步驟。

賦值兼容規則中所指的替代包括以下的情況:

???????? 派生類的對象可以賦值給基類對象。

????? ?? 派生類的對象可以初始化基類的引用。

?????? ? 派生類對象的地址可以賦給指向基類的指針。

在替代之后,派生類對象就可以作為基類的對象使用,但只能使用從基類繼承的成員。

二、多態

C++中所謂的多態(polymorphism)是指,由繼承而產生的相關的不同的類,其對象同一消息會作出不同的響應

如果父類指針指向的是父類對象則調用父類中定義的函數

如果父類指針指向的是子類對象則調用子類中定義的重寫函數

1解決方案:

???? ? C++中通過virtual關鍵字對多態進行支持

?????? 使用virtual聲明的函數被重寫后即可展現多態特性

將需要表現多態的父類中的函數聲明為虛函數,即在原有函數前加virtual關鍵字,并在子類函數中對父類虛函數進行重寫

2、多態成立的條件

?????? <1>、要有繼承

??????? <2>、要有虛函數重寫

??????? <3>、要有父類指針(引用)指向子類對象

3、多態的實現原理

????? 虛函數表和vptr指針

????? (1)當類中聲明虛函數時,編譯器會在類中生成一個虛函數表,

??????????????? 虛函數表是一個存儲類成員函數指針的數據結構;

?????????????? 虛函數表是由編譯器自動生成與維護的;

?????????????? virtual成員函數會被編譯器放入虛函數表中;

??????? (2)存在虛函數時,每個對象中都有一個指向虛函數表的指針(vptr指針)。

說明:

1. 通過虛函數表指針VPTR調用重寫函數是在程序運行時進行的,因此需要通過尋址操作才能確定真正應該調用的函數。而普通成員函數是在編譯時就確定了調用的函數。在效率上,虛函數的效率要低很多。

2.出于效率考慮,沒有必要將所有成員函數都聲明為虛函數.

3.C++編譯器,執行run函數,不需要區分是子類對象還是父類對象,而是直接通過p的VPTR指針所指向的對象函數執行即可。

4、驗證vptr指針的存在(從多個類繼承虛函數就有多個vptr指針)

???????? 兩個類:類A,類B,都只有數據成員int a,類A中有虛函數,類B中沒有。計算sizeof(A) sizeof(B)

32位:sizeof(A) =8?? sizeof(B)=4

64位:sizeof(A) =16 ? sizeof(B)=4? (64位一個指針占8字節,類的內存遵從字節對齊。故對齊后為8+8=16)

5、vptr指針初始化

vptr指針時分步驟初始化
?????? 1、調用父類構造函數在調用父類構造器時,會將vptr指針當做父類來處理。此時會臨時指向父類的虛函數表
?????? 2、處理自己構造函數,此時將子類對象的空間變成子類對象處理,vptr指針就從指向父類的表 變成 指向子類的表
注:不要在構造函數中處理業務。調用虛函數

6、父類指針步長和子類指針步長

父類指針步長為 sizeof(父類)

子類指針步長為 sizeof(子類)

注:當父類指針指向子類對象時,指針加加,為父類指針步長,寫一個可能并不是子類對象(父類所占空間小于等于子類空間,父類空間++,可能指針指向的并不是子類的開始地址)

驗證vptr指針存在代碼示例:

#if 1 #include<iostream> //http://www.mamicode.com/info-detail-1394321.html using namespace std; class Parent1 { public:virtual void func() {cout << "Parent" << endl;} private:int a; }; class Parent2 { public:virtual void func() {cout << "Parent" << endl;}virtual void func(int a) {cout << "Parent" << endl;} private:int a; }; class Parent3 { public:void func() {cout << "Parent" << endl;} private:int a; }; class Parent4 { public:void func() {cout << "Parent" << endl;} private:int a; };void test01() {Parent1 p1;Parent2 p2;Parent3 p3;Parent4 p4;cout << "sizeof(parent1)" << sizeof(p1) << endl; //多出來的字節是vptr指針所占用空間cout << "sizeof(parent2)" << sizeof(p2) << endl;cout << "sizeof(parent3)" << sizeof(p3) << endl;cout << "sizeof(parent4)" << sizeof(p4) << endl;} //字節對齊 /* sizeof(parent1)16 sizeof(parent2)16 sizeof(parent3)4 sizeof(parent4)4 */int main() {test01();return 0; } #endif

vptr指針初始化代碼示例:

#if 1 #include<iostream> using namespace std; //vptr指針時分步驟初始化 //1、調用父類構造函數 //2、處理自己構造函數 //不要在構造函數中處理業務。調用虛函數 class Parent { public:Parent(int a) {cout << "Parent(int)..." << endl;this->a = a;print(); //調用父類print還是子類print?父類printfunc();}virtual void print() {cout << "Parent::print()...a="<<this->a << endl;}void func() {cout << "Parent:func" << endl;} private:int a; }; class Child :public Parent { public:Child(int a, int b) :Parent(a) //在調用父類構造器時,會將vptr指針當做父類來處理//此時會臨時指向父類的虛函數表{//將子類對象的空間變成子類對象處理//vptr指針就從指向父類的表 變成 指向子類的表cout << "Child(int,int)..." << endl;this->b = b;print();func();Parent::func();}virtual void print() {cout << "Child::print()...b=" <<this->b<< endl;}void func() {cout << "Child:func" << endl;} private:int b; }; void test01() {Parent *pp = new Child(10, 20);pp->print(); //發生多態delete pp; } /* Parent(int)... Parent::print()...a=10 Parent:func Child(int,int)... Child::print()...b=20 Child:func Parent:func Child::print()...b=20 */ int main() {test01();return 0; } #endif

父類指針步長和子類指針步長示例:

#if 1 #include<iostream> using namespace std; #if 0 class Parent { public:Parent(int a) {cout << "Parent(int)..." << endl;this->a = a;}virtual void print() {cout << "Parent::print()...a=" << this->a << endl;}public:int a; }; class Child :public Parent { public:Child(int a) :Parent(a){cout << "Child(int,int)..." << endl;//print();}virtual void print() {cout << "Child::print()...b=" << this->a << endl;} }; void test01() {Child array[] = { Child(0),Child(1),Child(2) };for (int i = 0; i < 3; i++){array[i].print();} } void test02() {Child array[] = { Child(0),Child(1),Child(2) };Parent *pp = &array[0];pp->print();Child *cp = &array[0];cp->print();pp++; //pp+sizeof(Parent)cp++; //cp+sizeof(Child)pp->print();cp->print(); } void test03() {Child array[] = { Child(0),Child(1),Child(2) };Parent *pp = &array[0];int i = 0;for (pp = &array[0],i = 0; i < 3; i++, pp++) {pp->print();} } void test04() {Child array[] = { Child(0),Child(1),Child(2) };Parent *pp = &array[0];int i = 0;for (pp = &array[0], i = 0; i < 3; i++, pp++) {pp->print();} } #endif //在上面的代碼基礎上,在Child加int 運行報錯 當pp++時報錯 //因為 pp++; //pp+sizeof(Parent) // cp++; //cp+sizeof(Child) //兩個步長不一樣。 class Parent { public:Parent(int a) {cout << "Parent(int)..." << endl;this->a = a;}virtual void print() {cout << "Parent::print()...a=" << this->a << endl;}public:int a; }; class Child :public Parent { public:Child(int a) :Parent(a) {cout << "Child(int,int)..." << endl;//print();}virtual void print() {cout << "Child::print()...b=" << this->a << endl;} public:int b; }; void test01() {Child array[] = { Child(0),Child(1),Child(2) };for (int i = 0; i < 3; i++){array[i].print();} } /* Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Child::print()...b=0 Child::print()...b=1 Child::print()...b=2 */ void test02() {Child array[] = { Child(0),Child(1),Child(2) };Parent *pp = &array[0];pp->print();Child *cp = &array[0];cp->print();pp++; //pp+sizeof(Parent)cp++; //cp+sizeof(Child)pp->print();cp->print(); } /* 程序崩潰 Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Child::print()...b=0 Child::print()...b=0 */ void test03() {Child array[] = { Child(0),Child(1),Child(2) };Parent *pp = &array[0];int i = 0;for (pp = &array[0], i = 0; i < 3; i++, pp++) {pp->print();} } /* 程序崩潰 Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Child::print()...b=0 */ void test04() {Child array[] = { Child(0),Child(1),Child(2) };Child *cp = &array[0];int i = 0;for (cp = &array[0], i = 0; i < 3; i++, cp++) {cp->print();} } /* Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Parent(int)... Child(int,int)... Child::print()...b=0 Child::print()...b=1 Child::print()...b=2 */ int main() {//test01();//test02();test03();//test04();return 0; } #endif

代碼示例:

1、多態

#if 1 #include<iostream> #include<string> using namespace std; #if 0 class Hero { public:string kongfu; public:Hero(string kongfu) {this->kongfu = kongfu;}void fight() {cout << "英雄使出了" << this->kongfu << endl;} }; class Yuebuqun :public Hero { public:Yuebuqun(string kongfu):Hero(kongfu){}void fight() {cout << "Yuebuqun使出了" << this->kongfu << endl;} };class Linghuchong :public Yuebuqun { public:Linghuchong(string kongfu) :Yuebuqun(kongfu){}void fight(){cout << "Linghuchong使出了" << this->kongfu << endl;} }; void fight(Hero *hero) {cout << "調用打人的方法" << endl;hero->fight();//希望傳遞進來的如果是子類,調用子類的fight//如果傳遞進來的是父類, 調用父類的fight//這種行為就是 多態行為。 } void test01() {Hero h1("高招");h1.fight();Yuebuqun y1("y高招");y1.fight();Linghuchong l1("l高招");l1.fight(); } /* 英雄使出了高招 Yuebuqun使出了y高招 Linghuchong使出了l高招 */ void test02() {Yuebuqun *y1 = new Yuebuqun("y高招");y1->fight();Linghuchong *l1 = new Linghuchong("l高招");l1->fight();delete y1;delete l1; } /* Yuebuqun使出了y高招 Linghuchong使出了l高招 */ void test03() {Yuebuqun *y1 = new Yuebuqun("y高招");Linghuchong *l1 = new Linghuchong("l高招");fight(y1);fight(l1);delete y1;delete l1; } /* 調用打人的方法 英雄使出了y高招 調用打人的方法 英雄使出了l高招 */int main() {test01();//test02();//test03();return 0; } #endif class Hero { public:string kongfu; public:Hero(string kongfu) {this->kongfu = kongfu;}virtual void fight() {cout << "英雄使出了" << this->kongfu << endl;} }; class Yuebuqun :public Hero { public:Yuebuqun(string kongfu) :Hero(kongfu) {}void fight() {cout << "Yuebuqun使出了" << this->kongfu << endl;} };class Linghuchong :public Yuebuqun { public:Linghuchong(string kongfu) :Yuebuqun(kongfu) {}void fight() {cout << "Linghuchong使出了" << this->kongfu << endl;} }; void fight(Hero *hero) {cout << "調用打人的方法" << endl;hero->fight();//當把父類方法聲明為virtual時。可以實現傳進來誰,調用誰的方法//希望傳遞進來的如果是子類,調用子類的fight//如果傳遞進來的是父類, 調用父類的fight//這種行為就是 多態行為。 }void test04() {Yuebuqun *y1 = new Yuebuqun("y高招");Linghuchong *l1 = new Linghuchong("l高招");Hero *h1 = new Hero("h高招");fight(y1); fight(l1);fight(h1);delete y1;delete l1;delete h1; } /* 調用打人的方法 Yuebuqun使出了y高招 調用打人的方法 Linghuchong使出了l高招 調用打人的方法 英雄使出了h高招 */ int main() {test04(); }#endif

2、多態意義

#if 1 #include<iostream> using namespace std; //英雄類 class Hero { public:Hero() {cout << "dd" << endl;}virtual int getAd() {return 10;} }; class AdvHero:public Hero { public:virtual int getAd() { //virtual寫不寫都ok,寫上能加強代碼的可讀性return 1001;} }; //怪獸類 class Monster { public:int getAd() {return 1000;} };//戰斗方法 void playerFight(Hero *hp, Monster *mp) {if (hp->getAd() > mp->getAd()) { //hp->getAd()發生了多態cout << "英雄勝利,怪獸被打死了" << endl;}elsecout << "英雄死亡,怪獸贏了" << endl; }//2020年 //拓展新東西 不改變之前代碼 //多態意義 架構意義 class BugHero :public Hero { public:virtual int getAd() {cout << "調用BugHero方法" << endl;return 666666;} }; void test01() {Hero h;Monster m;playerFight(&h, &m);AdvHero advH;playerFight(&advH, &m);BugHero b;playerFight(&b, &m); }int main() {test01();Hero *h1[6]; //不調用析構函數 沒有具體指向//int array[][2];cout << "dddddddsfad" << endl;Hero h[5]; //調用5次構造函數 } /* dd 英雄死亡,怪獸贏了 dd 英雄勝利,怪獸被打死了 dd 調用BugHero方法 英雄勝利,怪獸被打死了 dddddddsfad dd dd dd dd dd */ #endif

多態原因:

#if 0 #include<iostream> using namespace std;class Parent { public:Parent(int a) {this->a = a;}virtual void func(int a) {cout << "Parent:func(int).." << endl;}void PrintP(){} private:int a; }; class Child :public Parent { public:Child(int a, int b) :Parent(b) {this->b = b;}virtual void func(int b) {cout << "Child::func(int)" << endl;}void func(int a, int b) {cout << "Child:func(int a,int b)" << endl;}void printC(){} private:int b; };void myFunc(Parent *p) {p->func(10); } void test01() {Parent *pp = new Parent(10);Parent *cp = new Child(100,200); //父類指針指向子類對象myFunc(pp);cout << "------" << endl;myFunc(cp); cp->PrintP(); //如果調用普通函數,編譯器根本不會查找虛函數表//只有你調用的是虛函數,才會去查找虛函數表 } int main() {test01();return 0; } #endif

?

總結

以上是生活随笔為你收集整理的C++基础15-类和对象之多态的全部內容,希望文章能夠幫你解決所遇到的問題。

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