c++單繼承與多繼承(包含虛擬函式與虛繼承的對比)
阿新 • • 發佈:2019-01-04
先來個概念分析題:
class Person
{
public:
void Show()
{
cout<<"Person::"<<_name<<endl;
}
protected:
int _id;
string _name;
};
struct Student : public Person
{
public:
void Show()
{
Person::_id = 10;
cout<<"Student::"<<_name<<endl;
}
public :
int _id;
};
// 隱藏--重定義
class AA
{
public:
void f()
{
cout<<"AA::f()"<<endl;
}
};
class BB : public AA
{
public:
void f(int a)
{
cout<<"BB::f()"<<endl;
}
};
int main()
{
AA aa;
BB bb;
aa.f();
bb.f();
/*bb.AA::f();*/
system("pause");
return 0;
// B C
/*A. BB裡面有兩個f函式,並且構成過載
B. BB裡面有兩個f函式,並且構成隱藏
C.上面程式碼編譯器不過
D.上面程式碼可以編譯通過,輸出AA::f().*/
}
圖解:
一、單繼承&多重繼承
1. 單繼承–一個子類只有一個直接父類時稱這個繼承關係為單繼承
2. 多繼承–一個子類有兩個或以上直接父類時稱這個繼承關係為多繼承
圖解:
二、菱形繼承(會帶來資料冗餘和二義性)————-用虛繼承來解決(virtual)
程式碼:
class A
{
public :
int _a;
};
class B : virtual public A
{
public:
int _b;
};
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;
D d1;
cout<<sizeof(D)<<endl;
B b;
b._a = 7;
b._b = 8;
cout<<sizeof(B)<<endl;
system("pause");
return 0;
}
圖解:
解決了這個問題,但開銷較大,這兩個指標簡稱尾虛基表指標
三、虛擬函式:
虛擬函式&多型
虛擬函式–類的成員函式前面加virtual關鍵字,則這個成員函式稱為虛擬函式。 虛擬函式重寫–當在子類的定義了一個與父類完全相同的虛擬函式時,則稱子類的這個函式重寫(也稱覆蓋)了父類的這個虛擬函式。
總結:
1. 派生類重寫基類的虛擬函式實現多型,要求函式名、引數列表、返回值完全相同。(協變除外)
2. 基類中定義了虛擬函式,在派生類中該函式始終保持虛擬函式的特性
3. 只有類的成員函式才能定義為虛擬函式。
4. 靜態成員函式不能定義為虛擬函式。
5. 如果在類外定義虛擬函式,只能在宣告函式時加virtual,類外定義函式時不能加virtual。
6. 建構函式不能為虛擬函式,雖然可以將operator=定義為虛擬函式,但是最好不要將operator=定義為虛擬函式,因為容易使用時容易引 起混淆。
7. 不要在建構函式和解構函式裡面呼叫虛擬函式,在建構函式和解構函式中,物件是不完整的,可能會發生未定義的行為。
8. 最好把基類的解構函式宣告為虛擬函式。(why?另外解構函式比較特殊,因為派生類的解構函式跟基類的解構函式名稱不一樣,但 是構成覆蓋,這裡是因為編譯器做了特殊處理)
未完待續