2

我知道C++中的物理和虛擬繼承。但是,我想知道是否可以通過任何設計模式或技巧來實現此模型。限制C++中虛擬基類的對象共享

E和F類以及這些類的基礎不應該被修改。想象它們來自外部庫。

E和F下面的所有內容都是開放的。這將是確定引進中間幫助類,非成員函數,模板......一切都將認識到這一點:

  BaseClass 
     /  \ 
     /  \ 
     A   A 
     /\  /\ 
    / \  / \ 
     B  C  B  D 
     \ /  \ /
     \/  \/
     E   F 
      \  /
      \  /
      \ /
      FinalClass 

注意,E和F不得共享A. FinalClass的確應該包含2 A. 我的問題是,E或F的創建將需要B,C和D虛擬繼承A.但是,如果A是虛擬基類,那麼編譯器只會在FinalClass中創建一個A對象而不是兩個不同的。

所以,我想你們中的許多人會在這裏推薦作文,而不是繼承。然而,構圖在這裏模仿「有一個」 - 關係而不是「是」 - 關係。 在解釋中,我希望FinalClass的行爲類似於E或F,包括能夠將其轉換爲這些類。

+0

你可以讓'A'爲班級模板嗎? – curiousguy

+0

讓我們假設我可以。它會改變什麼? B類也需要決定,它想繼承哪種A的專業化。 –

+0

如果你可以改變你的班級名稱(模板只是一種改變班級名稱的方法),你可以解決你的約束:模板 class B :public virtual A {' – curiousguy

回答

2

這個佈局在C++中是不可行的,即使有額外的幫助類也是如此。

B從A繼承的事實,並且您希望在C的一側和D在另一側共享A繼承,需要B,C和D實際上從A繼承。但是,A會是共享您的鑽石的兩個分支。

替代品

還有什麼替代方案?

  • 如果您設法打破鑽石左右分支之間的A分享,也可以打破共享基礎。

  • 如果您想介紹一些中介類A1,A2在您的分支機構實現左右的份額,你會但事實上,這兩個B的繼承卡無論是一個或另一個

  • 唯一的出路可能是有重複類B.

這最後的解決方案不能滿足您的要求,但將如下所示:

struct Base { int x; }; 
struct A : public virtual Base { int a; }; 
struct AC : public A{}; // synonym 
struct B : public virtual A { int b; }; 
struct BC : public virtual AC { int b; }; // !! clone !! 
struct C : public virtual AC { int c; }; 
struct D : public virtual A { int d; }; 
struct E : public BC, C { int e; }; 
struct F : public B, D { int f; }; 
struct Final : public E, F { }; 

而這裏訪問的承包商,客人:

Final f; 
f.x = 2; // unambiguous: there's onely one of it 
f.f = 1; 
f.e = 2; 
f.d = 3; 
f.c = 4; 
//f.b = 5; // ambiguous: there are two of it 
f.E::b = 5; // successful desambiguation 
f.F::b = 6; // successfuldesambiguation 
//f.a = 7; // ambiguous: there are two of it 
f.E::a = 7; // successful desambiguation 
f.F::a = 8; // successful desambiguation 

要回到你的問題陳述:你說你不能干預上述E和F.在這種情況下,你的選擇是非常有限的:

  • 你公開繼承
  • 你私下裏通過一些中介類

但效果會在共享相同的,如下面的代碼desmonstrates繼承(上上述一個的頂部):

class FI : private F // make F private 
{ public: 
    void set_xa(int u, int v) { x = u; a= v; } 
    void show_xa() { cout << "x:" << x << " a:" << a << endl; } 
}; 
class EI : private E // make E private 
{ 
public: 
    void set_xa(int u, int v) { x = u; a = v; } 
    void show_xa() { cout << "x:" << x << " a:" << a << endl; } 
}; 

struct Final3 : public EI, public FI { }; 

Final3 h; 
h.EI::set_xa(3, 4); 
h.FI::set_xa(5, 6); 
h.EI::show_xa(); 
h.FI::show_xa(); 
// the shared virtually inherited memebers are still shared ! 

結論:

通過繼承,您完全被E和F之上的設計所束縛,從而不被允許影響。

所以第一個問題是:

  • 你不能改變畢竟這種設計(即一個B的克隆)?
  • 難道兩個分支之間都有一個分歧(可能畢竟有理由)嗎?

如果答案是否定的這兩個問題,你必須去組成,並實現了一種proxy design pattern,你的組成對象是你的兩個組件的代理。

+0

如果A不是虛擬的,B和C如何或者B和D共享一個A? –

+0

@JackSabbath - 完全正確,對不起:我已經快速閱讀了這個問題,並沒有注意到兩個普通的B.我做了全面的編輯。 – Christophe

+0

非常感謝您的詳細解釋。我其實是問過這個問題的,因爲我是一個圖書館的作者,所以我想知道這個設計模式在實施之前是否是一個死衚衕。我認爲我的模型可以被實現,如果E從A中物理地派生,而B和C不是派生自A,而是使用好奇的循環模板模式來訪問A,而E繼承了它。圖的另一側也一樣。當然,B不會有相同的類型(CRTP專業化)。他們需要一個接口基類。我會一直忘記這種模式。 –