php 虚基类,1.9 多态
1.9 多態(tài)
返回目錄 1 面向?qū)ο蠹夹g(shù)
上一節(jié) 1.8 繼承
多態(tài)(Polymorphism)按字面的意思就是“多種狀態(tài)”。在面向?qū)ο笳Z言中,接口的多種不同的實(shí)現(xiàn)方式即為多態(tài)。
引用Charlie Calverts對(duì)多態(tài)的描述——多態(tài)性是允許你將父對(duì)象設(shè)置成為一個(gè)或更多的他的子對(duì)象相等的技術(shù),賦值之后,父對(duì)象就可以根據(jù)當(dāng)前賦值給它的子對(duì)象的特性以不同的方式運(yùn)作(摘自“Delphi4 編程技術(shù)內(nèi)幕”)。
簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
多態(tài)性在C++中是通過虛函數(shù)實(shí)現(xiàn)的。
多態(tài)按字面的意思就是多種形態(tài)。當(dāng)類之間存在層次結(jié)構(gòu),并且類之間是通過繼承關(guān)聯(lián)時(shí),就會(huì)用到多態(tài)。
C++ 多態(tài)意味著調(diào)用成員函數(shù)時(shí),會(huì)根據(jù)調(diào)用函數(shù)的對(duì)象的類型來執(zhí)行不同的函數(shù)。
虛基類
虛基類使得其派生類在間接地多次繼承本類時(shí),只繼承本類的一份成員,避免出現(xiàn)多次繼承產(chǎn)生多份拷貝的二義性。
源代碼
/* VirtualBaseClass.cpp 虛基類實(shí)例*/
#include
class Animal // 定義動(dòng)物類
{
protected:
int age; // 存儲(chǔ)年齡
public:
Animal(int age_t):age(age_t){}; // 參數(shù)列表初始化年齡
~Animal(){}; // 析構(gòu)函數(shù),這里用不上
};
class Bird:virtual public Animal // 鳥虛繼承動(dòng)物類
{
private:
int flyHight; // 定義鳥飛的高度
protected:
int getFlyHight(); // 獲取鳥飛的高度
public:
Bird(int flyHight_t, int age_t):flyHight(flyHight_t), Animal(age_t){}; // 參數(shù)列表初始化高度和年齡
~Bird(){}; // 析構(gòu)函數(shù)
};
int Bird::getFlyHight()
{
return flyHight; // 返回鳥飛的高度
}
class Fish:virtual public Animal // 魚虛繼承動(dòng)物類
{
private:
int divingDepth; // 定義魚潛水深度
protected:
int getDivingDepth(); // 獲取魚潛水深度
public:
Fish(int divingDepth_t, int age_t):divingDepth(divingDepth_t), Animal(age_t){}; // 參數(shù)列表初始化深度年齡
~Fish(){}; // 析構(gòu)函數(shù)
};
int Fish::getDivingDepth()
{
return divingDepth; // 返回魚潛的深度
}
class WaterBird:virtual public Bird, Fish // 多重繼承鳥和魚,此時(shí)間接地兩次繼承了動(dòng)物類,但是之前鳥和魚繼承時(shí)使用了虛繼承,因此此處默認(rèn)虛繼承,但是為了可讀性,這里最好寫上virtual
{
public:
WaterBird(int flyHight_t, int divingDepth_t, int age_t):Bird(flyHight_t, 5), Fish(divingDepth_t, 6), Animal(age_t){};
~WaterBird(){};
void displayInfos();
};
void WaterBird::displayInfos()
{
std::cout << "種族:飛魚" << std::endl;
std::cout << "年齡:" << age << std::endl;
std::cout << "最高飛行高度:" << getFlyHight() << std::endl;
std::cout << "最大潛水深度:" << getDivingDepth() << std::endl;
}
int main()
{
WaterBird wb(200, 50, 4);
wb.displayInfos();
return 0;
}
編譯運(yùn)行
種族:飛魚
年齡:4
最高飛行高度:200
最大潛水深度:50
我們發(fā)現(xiàn),在水鳥內(nèi)繼承鳥和魚的age時(shí),初始化的值分別為5和6,然后虛繼承動(dòng)物類的age時(shí),賦值為4,最終的結(jié)果為4。
這意味著我們通過創(chuàng)建虛基類繼承的成員默認(rèn)為最高基類的成員。
如果想要用鳥或者魚的age,需要使用域作用符。
虛函數(shù)
多態(tài)的本質(zhì)是同一個(gè)函數(shù)的多種形態(tài)
一般而言,C++支持的多態(tài)有兩種:
編譯時(shí)多態(tài)
靜態(tài)聯(lián)編在編譯時(shí)就已經(jīng)確定了多態(tài)性,一般通過重載進(jìn)行實(shí)現(xiàn);
運(yùn)行時(shí)多態(tài)
動(dòng)態(tài)聯(lián)編則在運(yùn)行時(shí)才能確定多態(tài)性 ,一般通過繼承和虛函數(shù)來實(shí)現(xiàn)。
若某個(gè)基類函數(shù)聲明為虛函數(shù),當(dāng)派生類使用基類指針或基類引用操作派生類對(duì)象時(shí),系統(tǒng)會(huì)自動(dòng)用派生類的同名函數(shù)代替基類虛函數(shù)。
如果基類函數(shù)沒有聲明為虛函數(shù),那么使用基類指針調(diào)用時(shí),調(diào)用到的是基類的函數(shù)。
源代碼
/* VirtualFunction.cpp 虛函數(shù)實(shí)例*/
#include
class BaseClass // 基類
{
private:
public:
BaseClass(){};
~BaseClass(){};
void speakNormal() // 提示信息的函數(shù),這里是普通函數(shù)
{
std::cout << "這里是基類!" << std::endl;
}
virtual void speakVirtual() // 提示信息的函數(shù),這里是虛函數(shù)
{
std::cout << "這里是基類!" << std::endl;
}
};
class DerivedClass:public BaseClass // 公有繼承
{
private:
public:
DerivedClass(){};
~DerivedClass(){};
void speakNormal() // 提示信息的函數(shù),這里是普通函數(shù)
{
std::cout << "這里是派生類!" << std::endl;
}
virtual void speakVirtual() // 提示信息的函數(shù),這里是虛函數(shù),虛函數(shù)默認(rèn)繼承時(shí)虛函數(shù),但是為了可讀性,建議在寫的時(shí)候加上virtual關(guān)鍵字
{
std::cout << "這里是派生類!" << std::endl;
}
};
int main()
{
DerivedClass dercs; // 創(chuàng)建一個(gè)普通的派生類對(duì)象
BaseClass* bascs = &dercs; // 創(chuàng)建一個(gè)基類指針指向剛剛的派生類對(duì)象
bascs->speakNormal(); // 基類指針調(diào)用普通函數(shù)
bascs->speakVirtual(); //基類指針調(diào)用虛函數(shù)
return 0;
}
編譯運(yùn)行
這里是基類!
這里是派生類!
我們可以看到:
使用普通函數(shù),基類指針調(diào)用的是基類同名函數(shù);
使用虛函數(shù),基類指針調(diào)用的是基類指針指向?qū)ο蟮耐瘮?shù)。
注意:派生類有時(shí)候需要銷毀資源,如果使用基類指針,那么必須要將基類析構(gòu)函數(shù)設(shè)為虛函數(shù),否則無法銷毀派生類資源。
另外,構(gòu)造函數(shù)不能作為虛函數(shù)。
純虛函數(shù)和抽象類
純虛函數(shù)是指如下模式的函數(shù):
virtual 返回值 函數(shù)名( 參數(shù)列表 ) = 0;
抽象類是指包含至少一個(gè)純虛函數(shù)的類:
class 類名
{
public:
virtual 返回值 函數(shù)名( 參數(shù)列表 ) = 0;
其它函數(shù)聲明
}
有時(shí)候我們不知道如何實(shí)現(xiàn)某個(gè)功能,比如要給一個(gè)形狀求面積,但是三角形和矩形的求面積方法并不相同,但是求面積又是必須要做的。
這種情況我們就可以使用純虛函數(shù)。
純虛函數(shù)只需聲明,無需實(shí)現(xiàn),具體的實(shí)現(xiàn)在其派生出子類以后再實(shí)現(xiàn),如果子類聲明了這個(gè)純虛函數(shù)但是沒有實(shí)現(xiàn),那么這個(gè)函數(shù)依然被視作純虛函數(shù)。
例如定義一個(gè)形狀類,里面有一個(gè)求面積的純虛函數(shù)作為接口,在三角形和矩形、圓形等不同的形狀里具體實(shí)現(xiàn)即可。
包含至少一個(gè)純虛函數(shù)的類是抽象類,抽象類不能實(shí)例化對(duì)象,必須要所有純虛函數(shù)實(shí)現(xiàn)的子類才能實(shí)例化對(duì)象,如果子類依然有純虛函數(shù),那么這個(gè)類依然是一個(gè)抽象類。
源代碼
/* AbstractClass.cpp 抽象類實(shí)例*/
#include
class Shapes // 定義形狀類
{
private:
public:
Shapes(){};
~Shapes(){};
virtual void disp() = 0; // 定義求面積的純虛函數(shù),此時(shí)形狀類作為抽象類,不能實(shí)例化對(duì)象,純虛函數(shù)要在派生類中實(shí)現(xiàn)
};
class Squera:public Shapes
{
public:
Squera(int length, int width); // (矩形長度, 矩形寬度)
~Squera(){};
class Squera_data // 定義一個(gè)內(nèi)部類
{
public:
int length_t; // 長
int width_t; // 寬
};
void disp(); // 實(shí)現(xiàn)基類的純虛函數(shù)
private:
Squera_data data_t; // 存儲(chǔ)矩形的數(shù)據(jù)
};
Squera::Squera(int length, int width)
{
data_t.length_t = length;
data_t.width_t = width;
}
void Squera::disp()
{
std::cout << "矩形面積為:" << data_t.length_t * data_t.width_t << std::endl;
}
class Triangle
{
private:
double bottomL_l; // 底邊
double heightL_l; // 高
class Triangle_run // 內(nèi)部類來運(yùn)算面積
{
private:
public:
Triangle_run(Triangle& tri_l){
std::cout << "三角形面積為:" << tri_l.bottomL_l * tri_l.heightL_l / 2 << std::endl;
}
};
public:
Triangle(double bottomL, double heightL):bottomL_l(bottomL), heightL_l(heightL){}; // (底, 高),三角形的屬性
~Triangle(){};
void disp(); // 實(shí)現(xiàn)純虛函數(shù)
};
void Triangle::disp()
{
Triangle_run tri_r_l(*this); // 把剛剛實(shí)例化的本類作為參數(shù)傳入
}
int main()
{
Squera squera_l(3, 4); // 矩形求面積實(shí)現(xiàn)
squera_l.disp();
Triangle tri_t(3, 4); // 三角形求面積實(shí)現(xiàn)
tri_t.disp();
return 0;
}
編譯運(yùn)行
矩形面積為:12
三角形面積為:6
我們發(fā)現(xiàn),我們實(shí)現(xiàn)了子類不同求面積的函數(shù),但是都以disp為名字,這樣,我們直接調(diào)用disp就可以在不同的派生類中做到同一件事情——求面積,盡管它們的具體實(shí)現(xiàn)方式不同。
值得注意的是,這里用到了內(nèi)部類,又稱嵌套類,在類中定義類,內(nèi)部類和外部類可以互相調(diào)用對(duì)方私有成員,但是內(nèi)部類調(diào)用外部類時(shí)需要傳入?yún)?shù)。
返回目錄 1 面向?qū)ο蠹夹g(shù)
上一節(jié) 1.8 繼承
參考資料:
《C++程序設(shè)計(jì)》傳智播客
博客園
CSDN
百度百科
總結(jié)
以上是生活随笔為你收集整理的php 虚基类,1.9 多态的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 内存与CPU的默契配合:如何判断搭配瓶颈
- 下一篇: 远程图片保存到服务器 php,保存远程图