柚子快報邀請碼778899分享:開發(fā)語言 C++:多態(tài)(繼承)
柚子快報邀請碼778899分享:開發(fā)語言 C++:多態(tài)(繼承)
hello,各位小伙伴,本篇文章跟大家一起學習《C++:多態(tài)》,感謝大家對我上一篇的支持,如有什么問題,還請多多指教 !
文章目錄
:maple_leaf:多態(tài)的概念:maple_leaf:繼承中的多態(tài)1.:leaves:虛函數(shù)表
:maple_leaf:多態(tài)原理
?多態(tài)的概念
在 C++ 中,多態(tài)性(Polymorphism)是面向?qū)ο缶幊讨幸粋€重要的概念,它允許使用統(tǒng)一的接口來操作不同的對象,從而提高代碼的靈活性、可維護性和可擴展性。多態(tài)性的實現(xiàn)依賴于兩種主要機制:編譯時多態(tài)性(靜態(tài)多態(tài)性)和運行時多態(tài)性(動態(tài)多態(tài)性)。
編譯時多態(tài)性(靜態(tài)多態(tài)性):在 C++ 中,編譯時多態(tài)性主要通過函數(shù)重載和運算符重載來實現(xiàn)。這種多態(tài)性是在編譯期間根據(jù)函數(shù)或運算符的參數(shù)類型和數(shù)量來選擇調(diào)用的函數(shù)版本,稱為靜態(tài)綁定或早期綁定。例如,函數(shù)重載允許在同一個作用域內(nèi)定義多個函數(shù)名相同但參數(shù)列表不同的函數(shù),編譯器會根據(jù)調(diào)用時的參數(shù)類型來選擇正確的函數(shù)。如下實現(xiàn)不同類型進行交換代碼:
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
運行時多態(tài)性(動態(tài)多態(tài)性):運行時多態(tài)性是通過虛函數(shù)和繼承關(guān)系來實現(xiàn)的。這種多態(tài)性允許在程序運行時根據(jù)對象的實際類型來調(diào)用對應的函數(shù),稱為動態(tài)綁定或后期綁定。在 C++ 中,通過在基類中將成員函數(shù)聲明為虛函數(shù)(使用 virtual 關(guān)鍵字),允許派生類覆蓋(override)這些虛函數(shù)。當通過基類指針或引用調(diào)用虛函數(shù)時,會根據(jù)實際指向的對象類型來決定調(diào)用哪個函數(shù)版本。
下面是一個簡單的示例,展示了 C++ 中的運行時多態(tài)性:
#include
using namespace std;
// Base class
class Animal {
public:
// Virtual function
virtual void speak() {
cout << "Animal speaks!" << endl;
}
};
// Derived class overriding the speak() function
class Dog : public Animal {
public:
// Override the speak() function
void speak() override {
cout << "Dog barks!" << endl;
}
};
// Derived class overriding the speak() function
class Cat : public Animal {
public:
// Override the speak() function
void speak() override {
cout << "Cat meows!" << endl;
}
};
int main() {
Animal *animal;
Dog myDog;
Cat myCat;
// Pointer to Dog object
animal = &myDog;
animal->speak(); // Output: Dog barks!
// Pointer to Cat object
animal = &myCat;
animal->speak(); // Output: Cat meows!
return 0;
}
在這個示例中:
Animal 類中的 speak() 函數(shù)被聲明為虛函數(shù)。Dog 和 Cat 類都重寫了 speak() 函數(shù),實現(xiàn)了不同的動作。在 main() 函數(shù)中,通過 Animal 類指針 animal 分別指向 Dog 對象和 Cat 對象,并調(diào)用它們的 speak() 函數(shù)。雖然指針類型是基類 Animal,但實際上根據(jù)指向的對象類型,調(diào)用的是對應的虛函數(shù)版本,展示了運行時多態(tài)性的特性。
通過多態(tài)性,C++ 提供了一種靈活且強大的機制,使得程序能夠根據(jù)對象的實際類型來決定調(diào)用哪個函數(shù)版本,從而實現(xiàn)代碼的重用性和擴展性。
?繼承中的多態(tài)
1.?虛函數(shù)表
先出一道題,32位機器下,sizeof(Base)答案是多少呢?
class Base
{
public:
virtual void Func1()
{
cout << "Func1()" << endl;
}
private:
int _b = 1;
};
答案是:8 可以看到,除了_b成員,還多一個__vfptr放在對象的前面(注意有些平臺可能會放到對象的最后面,這個跟平臺有關(guān)),對象中的這個指針我們叫做虛函數(shù)表指針(v代表virtual,f代表function)。
class Base
{
public:
virtual void Func1()
{
cout << "Base::Func1()" << endl;
}
virtual void Func2()
{
cout << "Base::Func2()" << endl;
}
void Func3()
{
cout << "Base::Func3()" << endl;
}
private:
int _b = 1;
};
class Derive : public Base
{
public:
virtual void Func1()
{
cout << "Derive::Func1()" << endl;
}
private:
int _d = 2;
};
int main()
{
Base b;
Derive d;
return 0;
}
派生類對象d中也有一個虛表指針,d對象由兩部分構(gòu)成,一部分是父類繼承下來的成員,虛表指針也就是存在部分的另一部分是自己的成員?;恇對象和派生類d對象虛表是不一樣的,這里我們發(fā)現(xiàn)Func1完成了重寫,所以d的虛表中存的是重寫的Derive::Func1,所以虛函數(shù)的重寫也叫作覆蓋,覆蓋就是指虛表中虛函數(shù)的覆蓋。重寫是語法的叫法,覆蓋是原理層的叫法。另外Func2繼承下來后是虛函數(shù),所以放進了虛表,F(xiàn)unc3也繼承下來了,但是不是虛函數(shù),所以不會放進虛表。虛函數(shù)表本質(zhì)是一個存虛函數(shù)指針的指針數(shù)組,一般情況這個數(shù)組最后面放了一個nullptr??偨Y(jié)一下派生類的虛表生成:a.先將基類中的虛表內(nèi)容拷貝一份到派生類虛表中 b.如果派生類重寫了基類中某個虛函數(shù),用派生類自己的虛函數(shù)覆蓋虛表中基類的虛函數(shù) c.派生類自己新增加的虛函數(shù)按其在派生類中的聲明次序增加到派生類虛表的最后。這里還有一個童鞋們很容易混淆的問題:虛函數(shù)存在哪的?虛表存在哪的? 答:虛函數(shù)存在虛表,虛表存在對象中。注意上面的回答的錯的。但是很多童鞋都是這樣深以為然的。注意虛表存的是虛函數(shù)指針,不是虛函數(shù),虛函數(shù)和普通函數(shù)一樣的,都是存在代碼段的,只是他的指針又存到了虛表中。另外對象中存的不是虛表,存的是虛表指針。
?多態(tài)原理
在CS2中,不同槍械的機動性不同:
class Gun
{
public:
virtual void Mobility(Gun& gun) = 0;
};
class AK47 : public Gun
{
public:
void Mobility(Gun& gun)
{
cout << "Mobility = " << _Mobility << endl;
}
private:
int _Mobility = 215;
};
class M4A4 : public Gun
{
public:
void Mobility(Gun& gun)
{
cout << "Mobility = " << _Mobility << endl;
}
private:
int _Mobility = 225;
};
void Func(Gun& gun)
{
gun.Mobility(gun);
}
int main()
{
AK47 ak47;
M4A4 m4a4;
Gun& ak = ak47;
Gun& m4 = m4a4;
Func(ak);
Func(m4);
return 0;
}
多態(tài)必須要滿足兩個條件: 1.必須通過基類的指針或者引用調(diào)用虛函數(shù) 2.被調(diào)用的函數(shù)必須是虛函數(shù),且派生類必須對基類的虛函數(shù)進行重寫
舉個簡單例子解釋,如下代碼:
class Base
{
public:
virtual void Func1()
{
cout << "Base::Func1()" << endl;
}
virtual void Func2()
{
cout << "Base::Func2()" << endl;
}
void Func3()
{
cout << "Base::Func3()" << endl;
}
private:
int _b = 1;
};
class Derive : public Base
{
public:
virtual void Func1()
{
cout << "Derive::Func1()" << endl;
}
private:
int _d = 2;
};
int main()
{
Base b;
Derive d;
Base& s1 = b;
Base& s2 = d;
s1.Func1();
s2.Func1();
return 0;
}
解釋:Derive繼承Base對Func1進行重寫,重寫后的虛函數(shù)會產(chǎn)生新的地址,放入虛表中Base&引用子類Derive對象,會發(fā)生切割,切割部分其實就是繼承Base部分,由于Derive對Func1進行重寫,所以s2虛表中的Func1是已經(jīng)重寫的。
圖解: 你學會了嗎? 好啦,本章對于《C++:多態(tài)(繼承)》的學習就先到這里,如果有什么問題,還請指教指教,希望本篇文章能夠?qū)δ阌兴鶐椭覀兿乱黄姡。。?/p>
如你喜歡,點點贊就是對我的支持,感謝感謝?。。?/p>
柚子快報邀請碼778899分享:開發(fā)語言 C++:多態(tài)(繼承)
相關(guān)鏈接
本文內(nèi)容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。