C++中實(shí)現(xiàn)多態(tài)有幾種方式小結(jié)
多態(tài)的概念
多態(tài) 指的是 具有繼承關(guān)系 的不同對(duì)象在調(diào)用同一函數(shù) 時(shí)形成的不同狀態(tài)!
舉個(gè)例子:比如我們平時(shí)買高鐵/火車票時(shí),不同的人買票買的結(jié)果都是不一樣的!學(xué)生是半價(jià)、成人是全價(jià)、軍人是軍人優(yōu)先票 等!而這三種對(duì)象本質(zhì)都是繼承自同一個(gè) Person 的父類,所以他們執(zhí)行同一操作時(shí)不同的結(jié)果就是多態(tài)!

• 構(gòu)成多態(tài)的兩個(gè)必要條件
1、必須通過(guò)基類/父類的 指針或者引用 調(diào)用虛函數(shù)
2、派生類必須得對(duì)基類的虛函數(shù)進(jìn)行重寫
舉個(gè)栗子先見一見:
class Person
{
public:
// 虛函數(shù)
virtual void BuyTicket()
{
cout << "Person::買票-成人-全價(jià)" << endl;
}
};
class Student : public Person // 構(gòu)成繼承關(guān)系
{
public:
// 虛函數(shù)
virtual void BuyTicket()
{
cout << "Student::買票-學(xué)生-半價(jià)" << endl;
}
};
int main()
{
// 父類對(duì)象的指針 調(diào)用虛函數(shù)
Person* pp = new Student;
pp->BuyTicket();
// 父類對(duì)象的引用 調(diào)用子類的對(duì)象
Student st;
Person& rp = st;
rp.BuyTicket();
Person p;
Person& r = p;// 父類對(duì)象的引用 調(diào)用虛函數(shù)
r.BuyTicket();
Person* ptr = &p;// 父類對(duì)象的指針 調(diào)用虛函數(shù)
ptr->BuyTicket();
return 0;
}此時(shí),不同的對(duì)象去以父類的指針/引用去調(diào)用虛函數(shù)時(shí)結(jié)果是不一樣的

下面由小編給大家總結(jié)一下C++實(shí)現(xiàn)多態(tài)的幾種方式!
一)虛函數(shù)(Virtual Functions)實(shí)現(xiàn)多態(tài)
概念:
虛函數(shù)是在基類中使用關(guān)鍵字virtual聲明的成員函數(shù)。當(dāng)一個(gè)類包含虛函數(shù)時(shí),編譯器會(huì)為該類創(chuàng)建一個(gè)虛函數(shù)表(v - table),這個(gè)表存儲(chǔ)了虛函數(shù)的地址。當(dāng)通過(guò)基類指針或引用調(diào)用虛函數(shù)時(shí),程序會(huì)根據(jù)對(duì)象的實(shí)際類型(即指針或引用所指向或引用的實(shí)際子類對(duì)象)來(lái)查找虛函數(shù)表,從而調(diào)用子類中重寫后的虛函數(shù),實(shí)現(xiàn)多態(tài)行為。
代碼示例:
class Shape
{
public:
virtual void draw() = 0;
};
class Circle : public Shape
{
public:
void draw() override
{
std::cout << "Drawing a circle." << std::endl;
}
};
class Rectangle : public Shape
{
public:
void draw() override
{
std::cout << "Drawing a rectangle." << std::endl;
}
};
在這個(gè)例子中,Shape是一個(gè)抽象基類,draw是一個(gè)純虛函數(shù)。Circle和Rectangle是Shape的子類,它們重寫了draw函數(shù)。當(dāng)使用
Shape* shapePtr;
shapePtr = new Circle();
shapePtr->draw();
或者
Shape circleObj;
Shape& shapeRef = circleObj;
shapeRef.draw();
(circleObj是Circle類的對(duì)象)這樣的方式調(diào)用draw函數(shù)時(shí),會(huì)根據(jù)對(duì)象是Circle還是Rectangle來(lái)動(dòng)態(tài)地調(diào)用相應(yīng)子類的draw函數(shù),實(shí)現(xiàn)多態(tài)。
二)函數(shù)指針實(shí)現(xiàn)多態(tài)(較少使用,但在某些特定場(chǎng)景下有效)
概念:
可以通過(guò)定義函數(shù)指針,讓函數(shù)指針指向不同的函數(shù)實(shí)現(xiàn)來(lái)達(dá)到類似多態(tài)的效果。函數(shù)指針可以根據(jù)具體的情況(如運(yùn)行時(shí)的條件)來(lái)改變它所指向的函數(shù),從而實(shí)現(xiàn)不同的行為。不過(guò)這種方式與虛函數(shù)相比,沒(méi)有自動(dòng)的動(dòng)態(tài)綁定機(jī)制,需要手動(dòng)管理函數(shù)指針的指向。
代碼示例:
// 定義函數(shù)指針類型,該函數(shù)接受無(wú)參數(shù),返回void
typedef void (*DrawFunction)();
class Shape
{
public:
DrawFunction drawFunction;
Shape(DrawFunction df) : drawFunction(df) {}
void draw()
{
drawFunction();
}
};
void drawCircle()
{
std::cout << "Drawing a circle using function pointer." << std::endl;
}
void drawRectangle()
{
std::cout << "Drawing a rectangle using function pointer." << std::endl;
}
int main()
{
Shape circleShape(drawCircle);
Shape rectangleShape(drawRectangle);
circleShape.draw();
rectangleShape.draw();
return 0;
}
在這個(gè)例子中,Shape類中有一個(gè)DrawFunction類型的函數(shù)指針drawFunction。在構(gòu)造函數(shù)中,可以傳入不同的函數(shù)來(lái)初始化這個(gè)函數(shù)指針。當(dāng)調(diào)用draw方法時(shí),就會(huì)執(zhí)行函數(shù)指針?biāo)赶虻暮瘮?shù)。通過(guò)這種方式,可以實(shí)現(xiàn)根據(jù)不同的對(duì)象(這里通過(guò)不同的構(gòu)造方式)來(lái)執(zhí)行不同的繪制函數(shù),達(dá)到類似多態(tài)的效果。不過(guò)這種方式需要手動(dòng)設(shè)置函數(shù)指針,而且對(duì)于繼承體系的支持不如虛函數(shù)方便。
代碼示例:
#include <iostream>
// 定義函數(shù)指針類型,該函數(shù)接受兩個(gè)整數(shù)參數(shù)并返回一個(gè)整數(shù)
typedef int (*MathOperation)(int, int);
int add(int a, int b)
{
return a + b;
}
int subtract(int a, int b)
{
return a - b;
}
int main()
{
MathOperation operation;
operation = add;
int result1 = operation(5, 3);
operation = subtract;
int result2 = operation(5, 3);
std::cout << "加法結(jié)果: " << result1 << std::endl;
std::cout << "減法結(jié)果: " << result2 << std::endl;
return 0;
}
在這個(gè)例子中,MathOperation是一個(gè)函數(shù)指針類型。通過(guò)將operation函數(shù)指針先后指向add函數(shù)和subtract函數(shù),實(shí)現(xiàn)了根據(jù)需要調(diào)用不同函數(shù)的效果,從而在一定程度上實(shí)現(xiàn)了多態(tài)。
三)模板(Templates)實(shí)現(xiàn)編譯時(shí)多態(tài)(也稱為參數(shù)化多態(tài))
概念:
模板是 C++ 中的泛型編程機(jī)制。雖然它不是真正的多態(tài)(因?yàn)樗窃诰幾g時(shí)確定具體的函數(shù)或類的版本,而不是運(yùn)行時(shí)),但在某些情況下可以實(shí)現(xiàn)類似多態(tài)的代碼復(fù)用和靈活性。通過(guò)模板,可以編寫通用的代碼,這些代碼可以根據(jù)不同的類型參數(shù)生成不同的具體實(shí)現(xiàn),從而適應(yīng)多種數(shù)據(jù)類型或類類型的需求。
代碼示例(函數(shù)模板):
template<typename T>
void draw(T& shape)
{
shape.draw();
}
class Circle
{
public:
void draw()
{
std::cout << "Drawing a circle using template." << std::endl;
}
};
class Rectangle
{
public:
void draw()
{
std::cout << "Drawing a rectangle using template." << std::endl;
}
};
int main()
{
Circle circle;
Rectangle rectangle;
draw(circle);
draw(rectangle);
return 0;
}
在這個(gè)例子中,draw是一個(gè)函數(shù)模板,它可以接受不同類型的參數(shù)(只要這個(gè)類型有draw方法)。當(dāng)傳入Circle或Rectangle對(duì)象時(shí),會(huì)在編譯時(shí)根據(jù)對(duì)象的類型生成對(duì)應(yīng)的draw函數(shù)調(diào)用,實(shí)現(xiàn)了對(duì)不同類型對(duì)象的通用處理,有點(diǎn)類似于多態(tài)的效果,但這種方式是基于編譯時(shí)的類型推導(dǎo),而不是像虛函數(shù)那樣的運(yùn)行時(shí)多態(tài)。
四)抽象基類與純虛函數(shù)結(jié)合實(shí)現(xiàn)多態(tài)(與虛函數(shù)方式緊密相關(guān))
概念:
抽象基類是包含純虛函數(shù)的類,不能被實(shí)例化。純虛函數(shù)是在基類中聲明但沒(méi)有定義的虛函數(shù),它強(qiáng)制子類必須重寫這個(gè)函數(shù)。通過(guò)這種方式,可以定義一個(gè)通用的接口,子類必須實(shí)現(xiàn)這個(gè)接口,從而實(shí)現(xiàn)多態(tài)。當(dāng)通過(guò)基類指針或引用調(diào)用這些純虛函數(shù)時(shí),會(huì)根據(jù)子類的實(shí)際實(shí)現(xiàn)來(lái)調(diào)用相應(yīng)的函數(shù)。
代碼示例(與前面虛函數(shù)示例結(jié)合):
class Shape
{
public:
virtual void draw() = 0;
};
這里Shape是抽象基類,draw是純虛函數(shù)。子類必須重寫draw函數(shù)才能實(shí)例化,這樣就確保了在通過(guò)Shape基類指針或引用調(diào)用draw函數(shù)時(shí),能夠根據(jù)具體子類的實(shí)現(xiàn)來(lái)獲得不同的繪制行為,實(shí)現(xiàn)多態(tài)。這種方式明確了接口規(guī)范,并且和虛函數(shù)的動(dòng)態(tài)綁定機(jī)制一起,是 C++ 實(shí)現(xiàn)多態(tài)的重要方式之一。
五)函數(shù)重載(Function Overloading)實(shí)現(xiàn)有限的多態(tài)性
概念:
函數(shù)重載是指在同一個(gè)作用域內(nèi),可以有多個(gè)同名函數(shù),它們的參數(shù)列表(參數(shù)個(gè)數(shù)、類型、順序)不同。當(dāng)調(diào)用一個(gè)重載函數(shù)時(shí),編譯器會(huì)根據(jù)傳入的實(shí)際參數(shù)來(lái)確定調(diào)用哪一個(gè)具體的函數(shù)版本。這種方式在一定程度上實(shí)現(xiàn)了多態(tài)性,因?yàn)橄嗤暮瘮?shù)名可以根據(jù)不同的參數(shù)類型執(zhí)行不同的操作。
代碼示例:
#include <iostream>
class Calculator
{
public:
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
};
int main()
{
Calculator calculator;
int intResult = calculator.add(3, 5);
double doubleResult = calculator.add(3.5, 2.5);
std::cout << "整數(shù)相加結(jié)果: " << intResult << std::endl;
std::cout << "浮點(diǎn)數(shù)相加結(jié)果: " << doubleResult << std::endl;
return 0;
}
在這個(gè)例子中,Calculator類中有兩個(gè)add函數(shù),一個(gè)用于整數(shù)相加,一個(gè)用于浮點(diǎn)數(shù)相加。編譯器會(huì)根據(jù)傳入add函數(shù)的參數(shù)類型來(lái)決定調(diào)用哪個(gè)版本,這就像一種簡(jiǎn)單的多態(tài),根據(jù)參數(shù)類型的不同選擇不同的操作方式。不過(guò),函數(shù)重載是在編譯時(shí)確定調(diào)用的函數(shù)版本,而不是像虛函數(shù)那樣在運(yùn)行時(shí)動(dòng)態(tài)綁定。
六)函數(shù)對(duì)象(仿函數(shù),F(xiàn)unctors):
原理:函數(shù)對(duì)象是一個(gè)類,它重載了函數(shù)調(diào)用運(yùn)算符operator()。這樣,這個(gè)類的對(duì)象就可以像函數(shù)一樣被調(diào)用。例如:
class AddFunctor
{
public:
int operator()(int a, int b) const
{
return a + b;
}
};
class SubtractFunctor
{
public:
int operator()(int a, int b) const
{
return a - b;
}
};
int main()
{
AddFunctor addObj;
SubtractFunctor subtractObj;
int result1 = addObj(3, 2);
int result2 = subtractObj(3, 2);
return 0;
}
應(yīng)用場(chǎng)景:在 STL 算法中廣泛使用。例如,std::sort函數(shù)可以接受一個(gè)比較函數(shù)對(duì)象來(lái)確定排序的順序。不同的比較函數(shù)對(duì)象可以實(shí)現(xiàn)不同的排序規(guī)則(如升序、降序),通過(guò)這種方式實(shí)現(xiàn)了基于不同規(guī)則的排序多態(tài)性。同時(shí),函數(shù)對(duì)象可以攜帶狀態(tài)(通過(guò)類的成員變量),這是函數(shù)指針?biāo)痪邆涞膬?yōu)勢(shì),在一些需要記錄中間狀態(tài)的場(chǎng)景中非常有用。
以上就是C++中實(shí)現(xiàn)多態(tài)有幾種方式小結(jié)的詳細(xì)內(nèi)容,更多關(guān)于C++實(shí)現(xiàn)多態(tài)方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)容的string
最近工作中使用C語(yǔ)言,但又苦于沒(méi)有高效的字符串實(shí)現(xiàn),字符串的拼接和裁剪都很麻煩,而且每個(gè)字符串都需要申請(qǐng)內(nèi)存,內(nèi)存的申請(qǐng)和釋放也很容易出bug,怎么高效的實(shí)現(xiàn)一個(gè)不需要處理內(nèi)存問(wèn)題并且可以動(dòng)態(tài)擴(kuò)容進(jìn)行拼接和裁剪的string呢?本文就來(lái)詳細(xì)講講2023-04-04
深入理解memmove()與memcpy()的區(qū)別以及實(shí)現(xiàn)方法
本篇文章是對(duì)memmove()與memcpy()的區(qū)別以及實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語(yǔ)言編程之預(yù)處理過(guò)程與define及條件編譯
這篇文章主要為大家介紹了C語(yǔ)言編程之預(yù)處理過(guò)程與define及條件編譯,文中通過(guò)圖文及示例代碼方式作了詳細(xì)的解釋,有需要的朋友可以借鑒參考下2021-09-09
深度解析C語(yǔ)言中數(shù)據(jù)的存儲(chǔ)
本文詳細(xì)介紹了C語(yǔ)言中數(shù)據(jù)的存儲(chǔ),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
C語(yǔ)言實(shí)現(xiàn)銷售管理系統(tǒng)

