哪些網(wǎng)站可以做問卷調(diào)查賺錢如何檢測(cè)網(wǎng)站是否安全
目錄
原理
總結(jié)
前面提到過,解決菱形繼承產(chǎn)生的數(shù)據(jù)二義性問題和數(shù)據(jù)冗余,就需要用到虛擬繼承,關(guān)于它是如何解決的,我們來一起研究。
class Person
{
public :string _name ; // 姓名
};
class Student : virtual public Person
{
protected :int _num ; //學(xué)號(hào)
};
class Teacher : virtual public Person
{
protected :int _id ; // 職工編號(hào)
};
class Assistant : public Student, public Teacher
{
protected :string _majorCourse ; // 主修課程
};
void Test ()
{Assistant a ;a._name = "peter";
}
原理
為了研究虛擬繼承原理,我們給出了一個(gè)簡化的菱形繼承繼承體系,再借助內(nèi)存窗口觀察對(duì)象成 員的模型。
class A
{
public:int _a;
};
// class B : public A
class B : virtual public A
{
public:int _b;
};
// class C : public A
class C : virtual public A
{
public:int _c;
};
class D : public B, public C
{
public:int _d;
};
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}
調(diào)試后打開內(nèi)存窗口,定位到對(duì)象d的地址去查看,可以看到?jīng)]有加virtual關(guān)鍵字時(shí),B類和C類實(shí)例化了兩份A類,這就是數(shù)據(jù)冗余。
下圖是菱形虛擬繼承的內(nèi)存對(duì)象成員模型:這里可以分析出D對(duì)象中將A放到的了對(duì)象組成的最下 面,這個(gè)A同時(shí)屬于B和C,那么B和C如何去找到公共的A呢?這里是通過了B和C的兩個(gè)指針,指 向的一張表。這兩個(gè)指針叫虛基表指針,這兩個(gè)表叫虛基表。虛基表中存的偏移量。通過偏移量 可以找到下面的A。
總結(jié)
1. 很多人說C++語法復(fù)雜,其實(shí)多繼承就是一個(gè)體現(xiàn)。有了多繼承,就存在菱形繼承,有了菱 形繼承就有菱形虛擬繼承,底層實(shí)現(xiàn)就很復(fù)雜。所以一般不建議設(shè)計(jì)出多繼承,一定不要設(shè)計(jì)出菱形繼承。否則在復(fù)雜度及性能上都有問題。
2. 多繼承可以認(rèn)為是C++的缺陷之一,很多后來的OO語言都沒有多繼承,如Java。
3.
繼承和組合 public繼承是一種is-a的關(guān)系。也就是說每個(gè)派生類對(duì)象都是一個(gè)基類對(duì)象。
組合是一種has-a的關(guān)系。假設(shè)B組合了A,每個(gè)B對(duì)象中都有一個(gè)A對(duì)象。
?優(yōu)先使用對(duì)象組合,而不是類繼承 。
繼承允許你根據(jù)基類的實(shí)現(xiàn)來定義派生類的實(shí)現(xiàn)。這種通過生成派生類的復(fù)用通常被稱 為白箱復(fù)用(white-box reuse)。術(shù)語“白箱”是相對(duì)可視性而言:在繼承方式中,基類的 內(nèi)部細(xì)節(jié)對(duì)子類可見 。繼承一定程度破壞了基類的封裝,基類的改變,對(duì)派生類有很 大的影響。派生類和基類間的依賴關(guān)系很強(qiáng),耦合度高。
對(duì)象組合是類繼承之外的另一種復(fù)用選擇。新的更復(fù)雜的功能可以通過組裝或組合對(duì)象 來獲得。對(duì)象組合要求被組合的對(duì)象具有良好定義的接口。這種復(fù)用風(fēng)格被稱為黑箱復(fù) 用(black-box reuse),因?yàn)閷?duì)象的內(nèi)部細(xì)節(jié)是不可見的。對(duì)象只以“黑箱”的形式出現(xiàn)。 組合類之間沒有很強(qiáng)的依賴關(guān)系,耦合度低。優(yōu)先使用對(duì)象組合有助于你保持每個(gè)類被 封裝。
實(shí)際盡量多去用組合。組合的耦合度低,代碼維護(hù)性好。不過繼承也有用武之地的,有 些關(guān)系就適合繼承那就用繼承,另外要實(shí)現(xiàn)多態(tài),也必須要繼承。類之間的關(guān)系可以用 繼承,可以用組合,就用組合。
// Car和BMW Car和Benz構(gòu)成is-a的關(guān)系class Car{protected:string _colour = "白色"; // 顏色string _num = "陜ABIT00"; // 車牌號(hào)};class BMW : public Car{public:void Drive() {cout << "好開-操控" << endl;}};class Benz : public Car{public:void Drive() {cout << "好坐-舒適" << endl;}};// Tire和Car構(gòu)成has-a的關(guān)系class Tire{protected:string _brand = "Michelin"; // 品牌size_t _size = 17; // 尺寸};class Car{protected:string _colour = "白色"; // 顏色string _num = "陜ABIT00"; // 車牌號(hào)Tire _t; // 輪胎};