多繼承及潛在問題
對象的繼承,指的是一個子類對象獲得父類對象的所有屬性和方法,並且可以在此基礎上拓展新的屬性和方法的一種行爲(個人理解,請勿當真。。)
那麼繼承可以一直進行,比如c繼承自b,b又繼承自a,那麼c的父類是b,b的父類是a,c的爺類是a,這好理解
但是值得注意的是,c++可以支持多繼承
這意味着
- 一個類可以有多個爹(父類)
- 爹類(父類)們,可能擁有共同的父類
- 那麼一個類可能會擁有多個爺類,這時候就會發生衝突,因爲爺類是同一個(即如下圖的a)
這個時候就會發生問題,因爲繼承的特性是:子類先創建父類的對象,在創建子類自己的屬性,那麼會創建兩個爺類對象,可是實際生產生活中一般只用一個爺類對象就夠了,這可能有些抽象,所以舉個例子:
- 有一個animal動物類,animal類有age年齡屬性
- cat類和dog類繼承自animal類
- 出現了新物種:catdog,catdog類繼承自cat類和dog類(多繼承)
按照繼承特性,繼承自cat和dog,cat和dog都會創建一個animal對象,所以catdog類有兩個animal對象,那麼catdog擁有兩個年齡屬性
可是客觀描述和實際編程,年齡都是唯一的變量,這就造成了衝突和客觀描述上的矛盾,而且造成了不必要的內存開銷
更致命的是,同名的age變量更容易造成衝突與bug
如下的代碼揭示了這種不合理的情況(即創建兩個animal對象)
#include <bits/stdc++.h>
using namespace std;
class animal
{
public:
int age;
animal(){cout<<"animal對象被創建"<<endl;}
};
class cat : public animal
{
public:
int c;
cat(){cout<<"cat對象被創建"<<endl;}
};
class dog : public animal
{
public:
int d;
dog(){cout<<"dog對象被創建"<<endl;}
};
class catdog : public cat, public dog
{
public:
int cd;
catdog(){cout<<"catdog對象被創建"<<endl;}
};
int main()
{
catdog cd;
return 0;
}
解決方案:虛繼承
因爲繼承的特性,子類在創建的時候,會先創建父類,所以上述問題會有兩個爺類的情況出現,而我們需要消滅一個爺
虛擬繼承的解決方法,是使得多繼承的時候,某個公共基類的成員在其派生類(子類)中只產生一個拷貝
實現方法:virtual
關鍵字
cat類和dog類在繼承基類animal的時候,加上virtual關鍵字,就會使得在後續的多繼承中,如果catdog類的父類cat和dog都繼承自animal,那麼只會產生一個animal對象而不是兩個
代碼
#include <bits/stdc++.h>
using namespace std;
class animal
{
public:
int age;
animal(){cout<<"animal對象被創建"<<endl;}
};
// 繼承基類時加上 virtual 關鍵字
class cat : virtual public animal
{
public:
int c;
cat(){cout<<"cat對象被創建"<<endl;}
};
// 繼承基類時加上 virtual 關鍵字
class dog : virtual public animal
{
public:
int d;
dog(){cout<<"dog對象被創建"<<endl;}
};
class catdog : public cat, public dog
{
public:
int cd;
catdog(){cout<<"catdog對象被創建"<<endl;}
};
int main()
{
catdog cd;
return 0;
}