天天看點

C++多态之繼承8-虛基類

在之前的文章中我們讨論了多重繼承,留下了一個鑽石問題,本文我們将繼續讨論這個問題,給出解決問題的方法。

虛基類

通過下面的例子我們來分析鑽石問題

class PoweredDevice
{
public:
    PoweredDevice(int nPower)
    {
		cout << "PoweredDevice: " << nPower << endl;
    }
};
 
class Scanner: public PoweredDevice
{
public:
    Scanner(int nScanner, int nPower)
        : PoweredDevice(nPower)
    {
		cout << "Scanner: " << nScanner << endl;
    }
};
 
class Printer: public PoweredDevice
{
public:
    Printer(int nPrinter, int nPower)
        : PoweredDevice(nPower)
    {
		cout << "Printer: " << nPrinter << endl;
    }
};
 
class Copier: public Scanner, public Printer
{
public:
    Copier(int nScanner, int nPrinter, int nPower)
        : Scanner(nScanner, nPower), Printer(nPrinter, nPower)
    {
    }
};
           

如果建立一個Copier對象,預設情況下會産生2份PoweredDevice的拷貝,一個來時Printer,另外一個來自Scanner。結構如下:

C++多态之繼承8-虛基類
int main()
{
    Copier cCopier(1, 2, 3);
}
           

上面的測試結果:

PoweredDevice: 3
Scanner: 1
PoweredDevice: 3
Printer: 2
           

如你所見PoweredDeivce被構造了2次。也許有時候你需要這樣,但是有時候你隻需要一份拷貝。為了共享一個基類,簡單的方法就是派生類的繼承方式上加上 virtual,這就是所謂的 虛基類。下面的例子會教你如何使用:

class PoweredDevice
{
};
 
class Scanner: virtual public PoweredDevice
{
};
 
class Printer: virtual public PoweredDevice
{
};
 
class Copier: public Scanner, public Printer
{
};
           

雖然隻會構造一個PoweredDevice對象,但是有個疑問就是誰來負責構造它呢?答案是Copier,Copier構造函數有責任來建立PoweredDevice。是以這是Copier直接調用非相鄰父類構造函數。

class PoweredDevice
{
public:
    PoweredDevice(int nPower)
    {
		cout << "PoweredDevice: " << nPower << endl;
    }
};
 
class Scanner: virtual public PoweredDevice
{
public:
    Scanner(int nScanner, int nPower)
        : PoweredDevice(nPower)
    {
		cout << "Scanner: " << nScanner << endl;
    }
};
 
class Printer: virtual public PoweredDevice
{
public:
    Printer(int nPrinter, int nPower)
        : PoweredDevice(nPower)
    {
		cout << "Printer: " << nPrinter << endl;
    }
};
 
class Copier: public Scanner, public Printer
{
public:
    Copier(int nScanner, int nPrinter, int nPower)
        : Scanner(nScanner, nPower), Printer(nPrinter, nPower), PoweredDevice(nPower)
    {
    }
};
           

結果:

PoweredDevice: 3
Scanner: 1
Printer: 2
           

PoweredDevice僅僅構造了一次,我們還需要注意的一些細節問題:

首先,虛基類在非虛基類之前建立,這樣確定了所有基類在他們的派生類之前被建立。

其次,Scanner和Printer的構造函數依然會調用PoweredDevice的構造函數,如果我們建立的是Copier執行個體,這些調用将會被忽略,因為Copier是建立PoweredDevice的責任人,而不是Scanner和Printer,但是如果我們建立Scanner或者Printer執行個體,virtual關鍵字将會被忽略,正常的繼承規則将适用,對PoweredDevice的構造函數調用将起作用。

最後,如果一個類繼承自一個或者多個類(這些類有虛父類),那麼最底層派生類負責構造虛基類。另外,這也适用于單一繼承情況:如果Copier單一繼承自Printer,Printer虛拟繼承自PoweredDevice,Copier依然負責構造PoweredDevice。

繼續閱讀