2016-07-25 52 views
2

我給下面的例子來說明我的問題:如何結合在C++中共享相同基類的兩個類?

class Base 
{ 
public: 
    virtual void do()=0; 
} 

class A: public Base 
{ 
public: 
    void do(); 
}; 

class B: public Base 
{ 
public: 
    void do(); 
} 

class AB: public Base 
{ 
public: 
void do() 
    { 
    a_.do(); 
    // if not succeed 
    { 
     b_.do(); 
    } 
    } 
private: 
A a_; 
B b_; 

} 

從上面的代碼中,我們可以看到,類來自同一個基類A, BAB。然而,類AB需要調用類A和類B。這是我的問題:AB這個班級的潛在問題是什麼?還有其他的選擇嗎?

一種選擇可能是:

class Base 
{ 
public: 
    virtual void do()=0; 
} 

class A: public Base 
{ 
public: 
    void do(); 
}; 

class B: public Base 
{ 
public: 
    void do(); 
} 

class AB: public A 
{ 
public: 
void do() 
    { 
    A::do(); 
    // if not succeed 
    { 
     b_.do(); 
    } 
    } 
private: 

B b_; 

} 
+6

你已經顯示了你想要做什麼,但不是_why_所以不清楚你想要解決什麼問題,所以很難說什麼是有效的替代方案。知道「do()」做什麼會有幫助,因爲它會告訴我們'AB'是否可以用'A'或'B'替代(用Liskov術語來說),所以從一個或者它們派生出來是否合理。 (N.B.'do'是一個關鍵字,所以不是一個有效的函數名稱,而且這個。do()'是無效的C++,它應該是'this-> A :: do();')。 –

+0

你可以做多重繼承,但它通常是一個不良的做法,並揭示了一個概念問題。你做得對。 –

+0

@PierreEmmanuelLallemant:不,MI在C++中不是邪惡的。建議閱讀:Bjarne Stroustroup的FAQ條目。 – lorro

回答

3

我不知道你真正想要達到什麼。但是如果你的所有類只能從Base獲得一個實例數據副本,你需要一個虛擬的基類。

從AB第一個例子的問題是,你有三個!乘以Base類的時間數據。一個來自繼承基礎,一個作爲成員B的一部分,它本身是從Base派生出來的,同樣來自成員A.那是你的意圖嗎?

我給你以下的內容,看看你如何在你的所有類實例中使用base的精確副本。也許這就是你想要得到的?

我向Base中添加一些數據,以瞭解在使用虛擬基類時建築是如何工作的。重要的是不要從直接繼承類的構造函數中調用基類構造函數!您需要直接從最外層的構造函數調用構造函數,如AB類構造函數所示!

作爲備註:虛擬基類只能在沒有其他設計符合的情況下使用。通常這種解決方案的需求表現出設計問題。但是一如既往的編程:如果這符合您的需求,那麼在技術上絕對可以。

class Base 
{ 
    private: 
     std::string text; 

    public: 
     Base(const std::string& str): text(str) {} 
     virtual void Do() { std::cout << text << std::endl; } 
}; 

class A: virtual public Base 
{ 
    public: 
     A():Base("Default from A") {} 
     void FuncA() { std::cout << "FuncA" << std::endl; } 
     void Do() { std::cout << "Via A" << std::endl; Base::Do();} 
}; 

class B: virtual public Base 
{ 
    public: 
     B(): Base ("Default from B") {} 
     void FuncB() { std::cout << "FuncB" << std::endl; } 
}; 

class AB: public A,B 
{ 
    public: 
     //Important to know that init of Base MUST be done from here and not from A nor B !! 
     AB(const std::string &s): Base(s) {} 
     void Do() { std::cout << "Via AB" << std::endl; Base::Do(); A::Do(); B::Do();} 
}; 

int main() 
{ 
    A a; 
    a.Do(); 
    std::cout << "####" << std::endl; 

    B b; 
    b.Do(); 
    std::cout << "####" << std::endl; 

    AB ab("Hallo"); 
    ab.Do(); 
    std::cout << "####" << std::endl; 
} 
+0

OP在'Base'裏沒有數據。 – Jarod42

+0

@ Jarod42我們不知道他想達到什麼目的。所以我增加了一些數據來提示施工和施工順序,希望這會有所幫助。他接受了答案,所以我相信我的想法有什麼不好的:-) – Klaus

-1

你應該從A和B繼承,而不是從基礎,因爲A和B已經這樣做。

+2

由於Base不是一個虛擬的基礎,這意味着有兩個基類,並且轉換到基地將是不明確的。這可能是一個可以接受的解決方案,但肯定有缺點。 (雖然我不是downvoter)。 –

+0

沒有想到這一點,感謝糾正我。 – sendra

3

AB類的潛在問題是什麼?

我不知道任何衆所周知的問題,必然會從您的設計中產生。你應該問自己:「爲什麼會有問題?」。

是否有其他的選擇?

有很多選擇。例如,AB都不包含任何狀態,因此您可以停止使用類來支持自由函數,並用函數指針替換動態綁定。

爲了能夠比較不同的選擇,你應該先決定你想要解決什麼問題。

相關問題