C++:类-多态的学习和使用
C++:類的學習和使用
- 類的多態
- 1.類的實例化
- 1.類中虛函數的使用實現多態
- C++ override使用詳解
類的多態
類作用域操作符 ::
C++是面向對象的編程語言,多態的使用是父類與子類關系最直接的表現:
c++中對于多態的理解就好比如下一個例子:
①我們說一種有四條腿的動物A,并進行簡單描述有四條腿的特征;
②甲猜了一種動物B,并且說了四條腿的具體特征;
③乙猜了一種動物C,并且說了四條腿的具體特征;
如上:動物A可以理解為基類,動物B.C都是子類,所以類的多態就表現在四條腿的特征(父類的(純)虛函數)上 B和C都繼承了A四條腿的特征,至于B和C因為各自物種差異而有所不同就對應了具體的子類中的(純)虛函數定義。
https://blog.csdn.net/lling_shan/article/details/105947287
分類:
靜態多態
:靜態多態是編譯器在編譯期間完成的,編譯器會根據實參類型來選擇調用合適的函數,如果有合適的函數可以調用就調,沒有的話就會發出警告或者報錯。
動態多態
:程序運行時根據基類的引用(指針)指向的對象來確定自己具體該調用哪一個類的虛函數
靜態多類:
/** 程序名:book236.cpp,此程序用于演示C++類的靜態多態。* 作者:C語言技術網(www.freecplus.net) 日期:20190525 */ #include <stdio.h> #include <string.h>class CGirl // 定義超女類 { public:char m_name[50]; // 姓名int m_age; // 年齡int m_height; // 身高,單位:厘米cmchar m_sc[30]; // 身材,火辣;普通;飛機場。char m_yz[30]; // 顏值,漂亮;一般;歪瓜裂棗。int Show() // 顯示超女基本信息的成員函數體{ printf("姓名:%s,年齡:%d,身高:%d,身材:%s,顏值:%s\n",m_name,m_age,m_height,m_sc,m_yz); } };class CKCon:public CGirl // 定義王妃類,從超女類繼承 { public:char m_ch[50]; // 稱號char m_palace[50]; // 居住的宮殿int m_sal; // 奉祿int Show() // 顯示王妃的稱號、宮殿和奉祿{ printf("姓名:%s,稱號:%s,棲:%s,奉祿:%d兩銀子。\n",m_name,m_ch,m_palace,m_sal); } };int main() {CKCon KCon;strcpy(KCon.m_name,"楊玉環"); KCon.m_age=28; KCon.m_height=168;strcpy(KCon.m_sc,"火辣"); strcpy(KCon.m_yz,"漂亮"); strcpy(KCon.m_ch,"楊貴妃");strcpy(KCon.m_palace,"華清宮"); KCon.m_sal=10000;CGirl *pGirl; // 基類的指針CKCon *pCon; // 派生類的指針pGirl=pCon=&KCon; // 都指向派生類pGirl->Show(); // 將調用的是基類的Show方法pCon->Show(); // 將調用的是派生類的Show方法 }輸出結果:
main函數中,創建的是CKCon對象,如果采用基類指針調用Show方法,變成了調用CGirl類的Show方法,而不是CKcon類的Show方法,因為pGirl是CGirl的指針,pGirl->Show方法在程序編譯期間就已經設置好了。
動態多態:
動態多態是在程序運行時根據基類的引用(指針)指向的對象來確定自己具體該調用哪一個類的虛函數。
讓我們對程序稍作修改,在CGirl類中,Show方法的聲明前放置關鍵字 virtual,如下所示:
virtual int Show() // 顯示超女基本信息的成員函數體其它的代碼都不變,編譯并運行,結果如下:
此時,編譯器看的是指針的內容,而不是它的類型。這就是多態的一般使用方式。
1.類的實例化
https://blog.csdn.net/qq_34637408/article/details/71189382
1.類中虛函數的使用實現多態
①類的多態
②1.首先看成員函數所在的類是否會作為基類。然后看成員函數在類的繼承后有無可能被更改功能,如果希望更改其功能的,一般應該將它聲明為虛函數。
3、應考慮對成員函數的調用時通過對象名還是通過基類指針或引用去訪問,如果是通過基類指針或引用去訪問的,則應當聲明為虛函數。
4.有時,在定義虛函數時,并不定義去函數體,即函數體是空的。它的作用只是定義了一個虛函數名,具體功能留給派生類去添加。
使用虛函數,系統要有一定的空間開銷。當一個類帶有虛函數時,編譯系統會為該類構造一個虛函數表,它是一個指針數組,存放每個虛函數的入口地址。系統在進行動態關聯時的時間開銷時很小的,因此,多態性時高效的。
原文鏈接:https://blog.csdn.net/wshngyf/article/details/48092679
純虛函數
一、定義
純 虛函數 是一種特殊的虛函數,它的一般格式如下:
在許多情況下,在基類中不能對虛函數給出有意義有實現,而把它說明為純虛函數,它的實現留給該基類的派生類去做。這就是純虛函數的作用。
二、引入原因
1、為了方便使用 多態 特性,我們常常需要在基類中定義虛擬函數。
2、在很多情況下,基類本身生成對象是不合情理的。
例如,動物作為一個基類可以派生出老虎、孔雀等子類,但動物本身生成對象明顯不合常理。
為了解決上述問題,引入了純虛函數的概念,將函數定義為純虛函數(方法:virtual ReturnType Function()= 0;),則編譯器要求在派生類中必須予以重載以實現多態性。同時含有純虛擬函數的類稱為 抽象類 ,它不能生成對象。這樣就很好地解決了上述兩個問題。
三、相似概念
1、多態性
指相同對象收到不同消息或不同對象收到相同消息時產生不同的實現動作。
C++支持兩種多態性:編譯時多態性,運行時多態性。
a.編譯時多態性:通過重載函數實現
b 運行時多態性:通過虛函數實現。
2、虛函數
虛函數是在基類中被聲明為virtual,并在派生類中重新定義的成員函數,可實現成員函數的動態重載
3、抽象類
包含純虛函數的類稱為抽象類。
由于抽象類包含了沒有定義的純虛函數,所以不能定義抽象類的對象。
注意:
(1)純虛函數沒有函數體;
(2)最后面的“=0”并不表示函數返回值為0,它只起形式上的作用,告訴編譯系統“這是虛函數”;
(3)這是一個聲明語句,最后有分號。
純虛函數只有函數的名字而不具備函數的功能,不能被調用。
純虛函數的作用是在基類中為其派生類保留一個函數的名字,以便派生類根據需要對他進行定義。如果在基類中沒有保留函數名字,則無法實現多態性。
如果在一個類中聲明了純虛函數,在其派生類中沒有對其函數進行定義,則該虛函數在派生類中仍然為純虛函數。
抽象類:
不用定義對象而只作為一種基本類型用作繼承的類叫做抽象類(也叫接口類),凡是包含純虛函數的類都是抽象類,抽象類的作用是作為一個類族的共同基類,為一個類族提供公共接口,抽象類不能實例化出對象。
純虛函數在派生類中重新定義以后,派生類才能實例化出對象。
總結:
1、派生類重寫基類的虛函數實現多態,要求函數名、參數列表、返回值完全相同。(協變除外)
2、基類中定義了虛函數,在派生類中該函數始終保持虛函數的特性。
3、只有類的非靜態成員函數才能定義為虛函數,靜態成員函數不能定義為虛函數。
4、如果在類外定義虛函數,只能在聲明函數時加virtual關鍵字,定義時不用加。
5、構造函數不能定義為虛函數,雖然可以將operator=定義為虛函數,但最好不要這么做,使用時容易混淆
6、不要在構造函數和析構函數中調用虛函數,在構造函數和析構函數中,對象是不完整的,可能會出現未定義的行為。
7、最好將基類的析構函數聲明為虛函數。(析構函數比較特殊,因為派生類的析構函數跟基類的析構函數名稱不一樣,但是構成覆蓋,這里編譯器做了特殊處理)
8、虛表是所有類對象實例共用的虛表剖析。
原文鏈接:https://blog.csdn.net/qq_36221862/article/details/61413619
class A{public:A();virtual ~A();void f1();virtual void f2();virtual void f3()=0;};//子類:class B : public A{public:B();virtual ~B();void f1();virtual void f2();virtual void f3();};// main 函數:int main(int argc, char* argv[]){A *m_j=new B();m_j->f1();m_j->f2();m_j->f3();delete m_j;return 0;}f1()是一個隱藏,關于函數的隱藏,可以參考其它詞條.
調用m_j->f1();會去調用A類中的f1(),它是在我們寫好代碼的時候就會定好的.
也就是根據它是由A類定義的,這樣就調用這個類的函數.
f2()是普通的重載.
調用m_j->f2();會調用m_j中到底保存的對象中,對應的這個函數.這是由于new的B對象.
f3()與f2()一樣,只是在基類中不需要寫函數實現.
虛函數和抽象基類的應用:
#include <iostream> using namespace std;//聲明抽象基類Shape class Shape { public:virtual float area()const //虛函數{return 0.0;}virtual void shapeName()const = 0;//純虛函數//shapeNamea函數的作用是輸出具體的形狀,在派生類中定義,因此聲明為純虛函數 };//聲明Point類 class Point:public Shape { public:Point(float a = 0.0, float b = 0.0){x = a;y = b;}void setPoint(float a, float b){x = a;y = b;}float getX()const{return x;}float getY()const{return y;}virtual void shapeName()const{cout<<"Point:";}friend ostream & operator <<(ostream &_cout, const Point &p){_cout<<"["<<p.x<<","<<p.y<<"]";return _cout;}protected:float x;float y; };//聲明Ciircle類 class Circle:public Point { public:Circle(float a = 0.0, float b = 0.0, float r = 0.0):Point(a, b),radius(r){}void setRadius(float r){radius = r;}float getRadius()const{return radius;}virtual float area()const{return 3.1415926*radius*radius;}virtual void shapeName()const{cout<<"Circle:";}friend ostream & operator <<(ostream &_cout, const Circle &c){_cout<<"["<<c.x<<","<<c.y<<"],r="<<c.radius;return _cout;}protected:float radius; };int main() {Point point(3.2, 4.5); // 建立Point類對象pointCircle circle(2.4, 1.2, 5.6); //建立Circle類對象circlepoint.shapeName(); //靜態關聯cout<<point<<endl;circle.shapeName(); //靜態關聯cout<<circle<<endl;Shape* pt; //定義基類指針pt = &point;pt->shapeName();cout<<"x="<<point.getX()<<",y="<<point.getY()<<endl;cout<<"area="<<pt->area()<<endl;pt = &circle; //指針指向Circle類對象pt->shapeName(); //動態關聯cout<<"x="<<circle.getX()<<",y="<<circle.getY()<<endl;cout<<"area="<<pt->area()<<endl;system("pause");return 0; }運行結果
結論:
(1)一個基類如果包含一個或一個以上純虛函數,就是抽象基類。抽象基類不能也沒必要定義對象。
(2)在類的層次結構中,頂層或最上面幾層可以是抽象基類。抽象基類體現了本類族中各類的共性,把各類中共有的成員函數集中在抽象基類中聲明。
(3)抽象基類是本類族的共公共接口,即就是從同一基類中派生出的多個類有同一接口。
原文鏈接:https://blog.csdn.net/qq_36221862/article/details/61413619
C++ override使用詳解
C++ override從字面意思上,是覆蓋的意思,實際上在C++中它是覆蓋了一個方法并且對其重寫,從而達到不同的作用。在我們C++編程過程中,最熟悉的就是對接口方法的實現,在接口中一般只是對方法進行了聲明,而我們在實現時,就需要實現接口聲明的所有方法。還有一個典型應用就是在繼承中也可能會在子類覆蓋父類的方法。
原文鏈接:https://blog.csdn.net/fanyun_01/article/details/79122136
總結
以上是生活随笔為你收集整理的C++:类-多态的学习和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【图像处理】纹理检测算法
- 下一篇: 【Linux】安装CUDA和cudnn