virtual inheritance 的妙用--------實現final類 (轉)

amyz發表於2007-11-26
virtual inheritance 的妙用--------實現final類 (轉)[@more@]

  virtual inheritance 的妙用--------實現final類
  cpp  to:cpp_bug@.com">cpp_bug@hotmail.com
一提起virtual inheritance,我們便會立刻把它與multiple inheritance 聯絡起來,因為multiple inheritance會產生一種DDD(dreadful diamond of derivation)的問題。透過virtual inheritance可以解決。關於這點不必多說,下面我們來看virtual inheritance的另外一個應用。
首先我們知道,virtual inheritance所帶來的一個效果就是由派生層次最深的類來完成根類子的建立,即由派生層次最深的類來根類子物件的構造,比方說:
class Base{};
class Derived1:virtual public Base{};
class Derived2:virtual public Base{};
class Mderived:public Derived1,public Derived2{};
對於上面這段程式碼,當用Mderived類構造物件的時候,因為這裡採用了virtual inheritance,並且Mderived類是派生層次最深的類,所以將會由Mderived來完成根類Base子物件的構建,而不是由類Derived1和Derived2來完成。
但是請你注意,並不一定每個派生層次最深的類都具有建立根類子物件的,所以final類的實現恰恰是巧妙的利用了這一點,我們先來看下面這段程式碼:
namespace Private
{
  class NoderivedHelper
  {
  NoderivedHelper(){}
  friend class Noderived;
  };
 }

class Noderived:private virtual Private::NoderivedHelper  //此處也可以是public繼承,沒
{  //有影響
  …
};
在上面這段程式碼中,Noderived類由於是NoderivedHelper類的友元類,因此它可以完成基類子物件的建立,也就是說它有許可權呼叫NoderivedHelper類的建構函式。但是如果我們想要從Noderived類進行派生,就會發生錯誤。為什麼呢?就是由於這裡採用了virtual inheritance,根類子物件必須由派生層次最深的類來建立的原因。比如:
class D:public Noderived{}
這裡根類子物件必須由D類來建立,但是由於D類不是NoderivedHelper的友元類,因此它沒有許可權呼叫NoderivedHelper類的建構函式,無法對根類子物件進行構建。我想大家對實現final類的基本原理應該已經理解,但是上面的程式碼由於有friend class Noderived;這一行,採用了硬編碼的方式,因此它的適用性很差,我們進行以下改進,去掉friend這一行:
namespace Private
{
  class NoderivedHelper
  {
  protected:  //這裡由private變為protected
NoderivedHelper(){}
  };
 }

class Noderived:private virtual Private::NoderivedHelper //這裡必須是private繼承
{
  …
};
ok,現在NoderivedHelper類的適用性明顯增強,而且也可以達到相同的效果,這又是為什麼呢?關鍵是這裡採用了私有繼承,從而NoderivedHelper類將作為Noderived類的私有內部,也就是說NoderivedHelper類的預設建構函式對於從Noderived類派生的類來說變為私有不可訪問。因此當派生層次最深的類建立根類子物件的時候就會出現沒有許可權呼叫根類建構函式的情況,從而發生錯誤。但是現在這個版本還有缺陷,看下面這種情況:
  class D: private virtual Private::NoderivedHelper ,public Noderived{}
現在類D就可以從Noderived類中進行派生。因為virtual inheritance使得只有一個根類子物件的副本,並且類D可以從第一個繼承中獲得建立根類子物件的許可權,因此就可以完成物件的構造
下面我們再來改進這個缺陷:
namespace Private
{
  class NoderivedHelper
  {
  protected:
NoderivedHelper(int){}
  };
 }

class Noderived:private virtual Private::NoderivedHelper
{
 public:
  Noderived():NoderivedHelper(0){} 
};
現在缺陷沒有了,透過那個dummy value,使得即使在class D: private virtual Private::NoderivedHelper ,public Noderived{}的情況下,類D也無法被正常的構造,因為類D在建立根類子物件的時候並不會為NoderivedHelper類的建構函式提供引數,所以無法完成物件的構造。
  現在我想大家已經清楚了virtual inheritance所帶來的又一應用了吧:)
  (全文完)

reference:

<> 第一期


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-984974/,如需轉載,請註明出處,否則將追究法律責任。

相關文章