多重繼承和虛基類,多重繼承基類
多重繼承描述的是有多個直接基類的類。多重繼承會帶來兩個主要的問題:
①從兩個不同的基類繼承同名方法;
②從兩個或更多相關基類那裡繼承同一個類的多個執行個體。例如:
class A
{
private:
string name;
int id;
public:
virtual void f();
...
};
class B:public A
{
private:
char ch;
public:
void f();
...
};
class C:public A
{
private:
double db;
public:
void f();
...
};
class D:public B,public C
{
public:
void f();
...
};
下面的將出現二義性:
D d;
A* a = &d;
通常這種賦值將把基類指標設定為派生對象中的基類對象的地址。但d中包含兩個A對象 ,有兩個地址可供選擇,所以應使用類型轉換來指定對象:
A* a1 = (B*)&d;
A* a2 = (C*)&d;
這將使得使用基類指標來引用不同的對象複雜化。
當C++引入多重繼承的時候,它引入了一種新技術----虛基類,是多重繼承成為可能。虛基類使得從多個類(它們的基類相同)派生出的對象只繼承一個基類對象。例如,通過在類聲明中使用關鍵字virtual,可以使A被用作B和C的虛基類(virtual和public的次序無關緊要):
class B:virtual public A{...};
class C:virtual public A{...};
使用虛基類時,需要對類建構函式採用一種新的方法。對於非虛基類,惟一可出現在初始化列表中的建構函式是即時基類建構函式。但這些建構函式可能需要將資訊傳遞給其基類。例如下面的,
class base{...};
class derived1:public base{...};
class derived2:public derived1{...};
derived2類的建構函式只能調用derived1類的建構函式,而derived1類的建構函式只能調用base類的建構函式。
如果A是虛基類,那麼這種資訊自動傳遞將不起作用。例如,對於下面的多重繼承建構函式:
D(const A& a,char c,double b)
:B(a,c),C(a,b){}
存在的問題是,自動傳遞資訊時,將通過2條不同的途徑(B和C)將a傳遞給A對象。為避免這種衝突,C++在基類是虛擬時候,禁止資訊通過中間類傳遞給基類。因此,上述建構函式將初始化成員ch和db,但a中的資訊將不會傳遞給對象A。不過,編譯器必須在構造派生對象之前構造基類基類對象組件;在上述情況下,編譯器將使用A的預設建構函式。如果不希望預設建構函式來構造基類對象,則需顯式地調用所需的基類建構函式。因此,建構函式應該是這樣:
D(const A& a,char c,double b)
:A(a),B(a,c),C(a,b){}
注意,這種用法是合法的,對於虛基類,必須這樣做,但是對於非虛基類,則是非法的。
究竟選用哪個方法?
對於單繼承來說,讓派生方法調用基類的方法是可以的,例如,對於B中的方法f():
void B::f(){ A::f();}
但是這種方法對於D範例無效。方法:
void D::f(){B::f();}將無效,因為它忽略了C組件。可以通過同時調用C版本的f()來補救:
void D::f(){B::f();C::f();}但是這樣做很可能會做一些同樣的工作。所以如何解決呢?使用模組化方式,而不是遞增方式,即提供一個只顯式A組件的方法和一個只顯示B組件或C組件的方法,然後在D方法中將組件組合起來。
混合使用虛基類和非虛基類:當類通過多條虛擬途徑和非虛擬途徑繼承某個特定的基類時,該類將包含一個表示所有的虛擬途徑的基類子物件和分表表示各條非虛擬途徑的多個基類子物件。
如果類從不同的類那裡繼承裡兩個多更多的同名成員,則使用該成員名時,如果沒有用類名進行限定,將導致二義性。但如果使用的是虛基類,則這樣做不一定會導致二義性。在這種情況下,如果某個名稱優先於其他所有名稱,則使用它時,即便不使用限定符,也不會導致二義性。
一個成員名如何優先於另一個成員名呢?衍生類別中的名稱優先於直接或間接祖先類中的相同名稱。例如,下面的定義中:
class B
{
public:
short q();
...
};
class C:virtual public B
{
public:
long q();
int omb();
...
};
class D:public C
{...};
class E:virtual public B
{
private:
int omb();
...
};
class F:public D,public E
{
...
}
類C中的q()定義將優先於類B中的q()定義,因為類C是從類B派生而來的。因此,F中的方法可以使用q()來表示C::q()。而任何一個omb()定義都不優先於其他omb()定義,因為C和E都不是對方的基類。所以,在F中使用非限定的omb()將導致二義性。
虛擬二義性規則與訪問規則無關,也就是說,即使E::omb()是私人的,不能再F類中直接存取,但使用omb()仍將導致二義性。同樣,即使C::q()是私人的,它也將優先於B::q()。在這種情況下,可以在類F中調用B::q(),但如果不限定q(),則將一位著要調用不可訪問的C::q()。
一個對於c++的虛基類多重繼承的問題
不虛繼承的意思不就是整個對象只有一個base1嗎?
C++中多繼承與虛基類別關係
多重繼承的時候,如果類C繼承了類B1和類B2,但類B1和類B2都繼承了類A。這樣基類A就會在衍生類別C中產生兩個基類子物件。
虛基類就用來解決這個問題的。
如果把類A作為類B1和類B2的虛基類,類B1和類B2作為類C的虛基類,基類A就只會在衍生類別C中產生一個基類子物件。
不知道這樣說,你能不能理解。