程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++語言筆記系列之十七——虛基類

C++語言筆記系列之十七——虛基類

編輯:C++入門知識

1.虛基類
考慮這樣一種情況:當某個類的部分或者全部直接基類是另一個共同基類派生而來,這些直接基類從上一級基類繼承而來的成員就一定擁有相同的名稱,這樣就會產生二義性問題。
解決辦法:當派生類和直接基類產生了二義性問題-->加類的作用域。
當派生類和間接基類產生了二義性問題-->虛基類。
2.虛基類的說明:
class 派生類名:virtual 訪問權限 基類名
{派生類定義};
注意:在定義派生類時將需要繼承的基類進行虛化聲明,虛基類的說明在派生類的定義中完成。
作用:將基類說明為虛基類之後,無論虛基類產生多少個派生類都不產生基類副本——多個派生類共用一個基類。
注意:若一個基類派生出多個派生類,必須在每個派生類的定義中將基類聲明為虛基類,任何一個派生類未進行聲明,那麼系統就會為該派生類產生基類副本。
example 1

class One
{int b;};
class Baseone:virtual public One
{int b1;};
class Basetwo:virtual public One
{int b2;};
class Basethree:public Baseone, public Basetwo
{};
3.虛基類的初始化
(1)派生類構造函數的調用順序:基類構造-->子對象構造-->派生類構造。
(2)虛基類的構造在非虛基類構造之前完成,若同一層有兩個虛基類,按說明順序調用構造。(3)虛基類只構造一次。
(4)若虛基類是非虛基類派生類,則先調用非虛基類構造。
(5)析構順序嚴格與構造相反。

example 2

#include
class Base1
{
public:
Base1()
{
cout<<"Base1 construction."< }
};
class Base2
{
public:
Base2()
{
cout<<"Base2 construction."< }
};
class Level1:public Base2, virtual public Base1
{
public:
Level1() {cout<<"Level1 construction."< };
class Level2:public Base2, virtual public Base1
{
public:
Level2() {cout<<"Levle2 construction."< };
class Toplevel:public Level1, virtual public Level2
{
public:
Toplevel() {cout<<"Toplevel construction."< };

int main()
{
Toplevel obj;
}
程序輸出:
Base1 construction.
Base2 construction.
Levle2 construction.
Base2 construction.
Level1 construction.
Toplevel construction.
分析:obj是Toplevel的對象,Toplevel有一個虛基類和一個非虛基類,按照規則,先構造虛基類,即Level2。而Level2又有一個虛基類和非虛基類,同樣先構造虛基類,即Base1,Base1構造之後會構造Level2的非虛基類Base2,最後才構造Level2。至此,Toplevel的虛基類構造完成,下面該構造TopLevel的非虛基類Level1,首先構造器虛基類Base1,因為Base1已經構造過,所以不再構造,下面是Base2,最後是Level1。最後一步就是
構造Toplevel了。

example 3

#include
class A
{
public:
A(char i) {cout<<"A construction "< ~A() {cout<<"A destruction."< };
class B:virtual public A
{
public:
B(char i, char j):A(i)//由於虛基類A屬於有參構造,所以必須在派生類B中調用A的構造
{
cout<<"B construction "< }
~B() {cout<<"B destruction."< private:
char b;
};
class C:virtual public A
{
public:
C(char i, char j):A(i)//盡管派生類C並沒有調用虛基類A的構造函數,因為在派生類B中已經
//調用過,但C的構造函數中必須要聲明對虛基類A的有參調用。
{
cout<<"C construction "< }
};
class D:public B, public C
{
public:
D(char i, char j, char k, char l, char m, char n):
C(k,l), B(i,j), A(n), aa(m)
{
cout<<"D construction."< }
private:
A aa;
};

int main()
{
D obj('a', 'b', 'c', 'd', 'e', 'f');
}
程序輸出:
A construction f
B construction b
C construction d
A construction e
D construction.
A destruction.
B destruction.
A destruction.
注意:在D的構造函數中有A(i),這個位置加上A(i)是必須的。A的構造用的是f。
分析:在D構造中加A(i)是必須的,因為A的構造會在B和C的構造之前,也就是說傳給B和C的參數是不能用來構造A的,所以A的有參構造必須來自於D,並且取的是D傳遞給A的參數值。
4.調用順序
(1)所有虛基類構造函數按照它們被繼承的順序構造。
(2)所有非虛基類的構造函數按照它們被繼承的順序構造。
(3)所有子對象按照它們的聲明順序構造。
(4)派生類自己的構造:
A.在一個初始化列表中同時出現虛基類和非虛基類成員函數的調用,虛基類優先於非虛基類。
B.同一層的虛基類按照說明順序調用構造,非虛基類按照繼承順序調用構造。
C.所有的虛基類在繼承中只構造一次,虛基類的每個子對象都要調用一次構造。
5.虛基類的賦值兼容規則
(1)派生類地址可以賦值給虛基類指針。
(2)虛基類引用可以引用派生類對象。(都是大的可以賦值給小的)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved