簡體   English   中英

虛擬繼承-與其他派生類共享的基類

[英]Virtual Inheritance - base shared with other derived classes

Bjarne Stroustrup寫道:

在為具有虛擬基礎的類定義函數時,程序員通常無法知道該基礎是否將與其他派生類共享。 當實現要求將基類函數精確調用一次的服務時,這可能是個問題。

我不明白這句話。 可能會出現什么問題?

為了解釋這一點,他給出了一個奇怪的例子

class A {                             // no constructor
    // ...
};
class B {
  public:
    B();                              // default constructor
    // ...
};
class C {
  public:
    C(int);                           // no default constructor
};
class D: virtual public A, virtual public B, virtual public C
{
    D() { /*... */ }                  // error: no default constructor for C
    D(int i) : C(i i) { /*... */ };   // ok
    // ...
};   

這里有關系嗎?

假設您有一個虛擬基類,需要通過調用.initialize(42)來初始化一次。 關鍵是,您不應該由哪個派生類調用它。

struct X : virtual A {
  X() { 
     // here 
  }
};

struct Y : virtual A {
  Y() { 
     // or here 
  }
};

struct Z : X, Y {
  // what about this    
};

在這種情況下,正確的答案是“有時在這里,有時在那里”,但是您不知道是哪種情況(取決於哪個類是最派生的子對象)。

C ++為構造函數st解決了此問題。 所有虛擬基礎的構造函數在派生最多的子對象的構造函數中僅被調用一次; 層次結構中的任何構造函數都必須准備好調用虛擬基礎構造函數(盡管在運行時可能不會發生)。

想象這樣的情況:

struct Base
{
    Base() { }
    virtual void call_me();
};

struct A : virtual Base { A() { call_me(); } };
struct B : virtual Base { B() { call_me(); } };

struct Derived : A, B
{
    Derived()
    :  Base()       // virtual base is construced in most-derived
    ,  A()
    ,  B()
    {  }
};

現在,警告是關於中間類AB可能假設它們是唯一調用Base::call_me() 如果它們對Base的繼承是非虛擬的,那的確是這樣,因為AB都有自己的唯一基類。 但是,對於虛擬繼承, AB來決定誰作為基類最終取決於誰,因為只有最終類Derived安裝了由所有中介共享的實際的單個基類。 因此,在我們的例子中, 無論AB最終調用call_me() 相同的基對象。

道德是與虛擬基類有關的操作應由派生程度最高的類負責。 由於這不是一個嚴格的概念,並且繼承實際上可以無限期地擴展,所以這是一個滑坡。 虛擬多重繼承是一個復雜的概念。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM