C++中的多重继承
文章目錄
- 1 C++中的多重繼承
- 2 C++中多重繼承帶來的問題
- 2.1 同一個對象的地址不同
- 2.2 帶來數據冗余的問題
- 2.3 可能產生多個虛函數表
- 3 工程開發中多重繼承的方式
1 C++中的多重繼承
C++支持編寫多重繼承的代碼:
- 一個子類可以擁有多個父類。
- 子類擁有所有父類的成員變量。
- 子類繼承所有父類的成員函數。
- 子類對象可以當作任意父類對象使用。
多重繼承的語法規則:
多繼承的構造函數的調用順序:
- 父類構造函數的調用順序和和它們在子類構造函數中出現的順序無關,而是和聲明子類時父類出現的順序相同。
2 C++中多重繼承帶來的問題
2.1 同一個對象的地址不同
看如下代碼:
#include <iostream> #include <string>using namespace std;class BaseA {int ma; public:BaseA(int a){ma = a;}int getA(){return ma;} };class BaseB {int mb; public:BaseB(int b){mb = b;}int getB(){return mb;} };class Derived : public BaseA, public BaseB {int mc; public:Derived(int a, int b, int c) : BaseA(a), BaseB(b){mc = c;}int getC(){return mc;}void print(){cout << "ma = " << getA() << ", "<< "mb = " << getB() << ", "<< "mc = " << mc << endl;} };int main() {cout << "sizeof(Derived) = " << sizeof(Derived) << endl; // 12Derived d(1, 2, 3);d.print();cout << "d.getA() = " << d.getA() << endl;cout << "d.getB() = " << d.getB() << endl;cout << "d.getC() = " << d.getC() << endl;cout << endl;BaseA* pa = &d;BaseB* pb = &d;cout << "pa->getA() = " << pa->getA() << endl;cout << "pb->getB() = " << pb->getB() << endl;cout << endl;void* paa = pa;void* pbb = pb;if( paa == pbb ){cout << "Pointer to the same object!" << endl; }else{cout << "Error" << endl;}cout << "pa = " << pa << endl;cout << "pb = " << pb << endl;cout << "paa = " << paa << endl;cout << "pbb = " << pbb << endl; return 0; }執行結果如下:
問題分析:
2.2 帶來數據冗余的問題
多重繼承可能帶來冗余的成員:
實現代碼如下:
打印結果:
當多重繼承關系出現閉合時將產生數據冗余的問題!
解決方案:虛繼承
對于虛繼承:
- 虛繼承能夠解決數據冗余的問題。
- 中間層父類不再關心頂層父類的初始化。
- 最終子類必須直接調用頂層父類的構造函數。
上面那個被共享的基類(People)就稱為虛基類(Virtual Base Class)。
解決方案代碼:
#include <iostream> #include <string>using namespace std;class People {string m_name;int m_age; public:People(string name, int age){m_name = name;m_age = age;}void print(){cout << "Name = " << m_name << ", "<< "Age = " << m_age << endl;} };class Teacher : virtual public People { public:Teacher(string name, int age) : People(name, age){} };class Student : virtual public People { public:Student(string name, int age) : People(name, age){} };class Doctor : public Teacher, public Student { public:Doctor(string name, int age) : Teacher(name, age), Student(name, age), People(name, age){} };int main() {Doctor d("Delphi", 33);d.print();return 0; }在架構設計中需要繼承時,我們是無法確定使用直接繼承還是虛繼承!虛繼承會使得架構設計可能出現問題。
2.3 可能產生多個虛函數表
多重繼承可能產生多個虛函數表:
示例代碼如下:
輸出結果如下:
修改后的代碼:
輸出結果:
3 工程開發中多重繼承的方式
工程中我們使用如下“單繼承多接口”的方式使用多重繼承:
對于正確的使用多重繼承,一些有用的工程建議:
- 先繼承自一個父類,然后實現多個接口。
- 父類中提供equal()成員函數。
- equal()成員函數用于判斷指針是否指向當前對象。
- 與多重繼承相關的強制類型轉換用dynamic_cast完成。
示例代碼:
#include <iostream> #include <string>using namespace std;class Base { protected:int mi; public:Base(int i){mi = i;}int getI(){return mi;}bool equal(Base* obj){return (this == obj);} };class Interface1 { public:virtual void add(int i) = 0;virtual void minus(int i) = 0; };class Interface2 { public:virtual void multiply(int i) = 0;virtual void divide(int i) = 0; };class Derived : public Base, public Interface1, public Interface2 { public:Derived(int i) : Base(i){}void add(int i){mi += i;}void minus(int i){mi -= i;}void multiply(int i){mi *= i;}void divide(int i){if( i != 0 ){mi /= i;}} };int main() {Derived d(100);Derived* p = &d;Interface1* pInt1 = &d;Interface2* pInt2 = &d;cout << "p->getI() = " << p->getI() << endl; // 100pInt1->add(10);pInt2->divide(11);pInt1->minus(5);pInt2->multiply(8);cout << "p->getI() = " << p->getI() << endl; // 40cout << endl;cout << "pInt1 == p : " << p->equal(dynamic_cast<Base*>(pInt1)) << endl;cout << "pInt2 == p : " << p->equal(dynamic_cast<Base*>(pInt2)) << endl;return 0; }參考資料:
總結
- 上一篇: C++中的接口
- 下一篇: 交行青年卡怎么样 办理条件额度解读