2013-12-13 30 views
4

我使用阿庫具有許多類型,其全部由相同的2個接口派生:存儲多重繼承在容器對象

class Huey : public IDuck, public ICartoonCharacter 
{ 
... 
}; 

class Dewey : public IDuck, public ICartoonCharacter 
{ 
... 
}; 

class Louie : public IDuck, public ICartoonCharacter 
{ 
... 
}; 

我想存儲在包裝上述所有類型的對象類和包裝類中的對象粘貼到容器中。當然,我應該能夠從我的包裝類中調用屬於這兩個接口的方法。

我在這裏有什麼選擇?我能想到的存儲IDuck *在我的包裝和

  • 的dynamic_cast-ING使用類似boost::any同時使我的包裝類模板,與一對夫婦的static_asserts以保證模板參數ICartoonCharacter,或
  • 繼承自IDuckICartoonCharacter

但無論選擇特別上訴。有任何想法嗎?

two interfaces, multiple inheritance combine into one container?是一個相關的問題,但詹姆斯甘孜的回答沒有爲我工作,因爲我無法改變的3類。

編輯:不要經常使用多重繼承,忘記語法。現在從兩個接口繼承public ly。

編輯:現在使用的dynamic_cast代替的static_cast(這將無法正常工作)。

編輯:我發現這兩個邁克·西摩的馬蒂厄和M的答案有前途的。一旦我完成了編碼,我會接受他們的答案之一。謝謝!

+2

不能從'IDuck *'的static_cast到不相關類型的'ICartoonCharacter *'。你可以通過dynamic_cast提供'IDuck'至少有一個虛函數。 –

+0

如果可以使用'dynamic_cast',我通常會使用第一個選項(請參閱上面的@SteveJessop註釋)。 –

+0

我不確定,但我認爲,即使您的孩子班級不能從單親父母繼承(他們繼承了當前的父母),您仍然可以從引入這樣的班級中受益(例如'ICartoonDuck')。 )您可以將ICartoonDuck存儲在您的容器中,而不用擔心內存佈局問題。 (儘管如此,你仍然需要不安全的強制轉換;這仍然是一個黑客攻擊)。 – yzt

回答

5

一個簡單的選擇是兩個指針存儲在所述包裝:

struct CartoonDuckWrapper { 
    IDuck * duck; 
    ICartoonCharacter * toon; 

    template <class CartoonDuck> 
    CartoonDuckWrapper(CartoonDuck & cd) : duck(&cd), toon(&cd) {} 
}; 

有使用static_assert檢查CartoonDuck繼承兩個基類沒有特別的需要,儘管這可能會給稍微好一點的診斷不是簡單地讓指針轉換失敗。

如果基類是多態的(它們可能是接口,它們可能是),您可以通過使用dynamic_cast將一個指針轉換爲另一個來節省一個指針的空間,以換取運行時成本。 static_cast不能用於基類之間的這種「交叉投射」。

2

創建一箇中間類:

class ILuckyDuck: public IDuck, ICartoonCharacter //... 

與:

class Huey : public ILuckyDuck //... 

,並存儲:

std::vector<std:shared_ptr<ILuckyDuck>> donald; 
+0

op已經提到過,這對他來說是不可能的。 –

+1

但是'Huey'不是'ILuckyDuck',所以這沒有幫助。 –

+1

但是提問者明確表示他不能改變'Huey'類,所以這仍然沒有幫助。 –

3

作爲編程中的所有問題,您可以通過添加一個間接級別來解決它。

class ICartoonDuck: public IDuck, public ICartoonCharacter {}; 

template <typename T> 
class CartoonDuck: public ICartoonDuck { 
public: 
    explicit CartoonDuck(T t): _t(std::move(t)) {} 

    // IDuck interface 
    virtual void foo() override { t.foo(); } 

    // ICartoonCharacter interface 
    virtual void bar() override { t.bar(); } 

private: 
    T _t; // or any ownership scheme that makes sense 
}; // class CartoonDuck 

template <typename T> 
CartoonDuck<T> makeCartoonDuck(T t) { return CartoonDuck(std::move(t)); } 

template <typename T, typename... Args> 
std::unique_ptr<CartoonDuck<T>> makeUniqueCartoonDuck(Args&&...) { 
    return std::unique_ptr<CartoonDuck<T>>(new T(std::forward<Args>()...); 
} 

現在,您可以愉快地在您的容器中存儲std::unique_ptr<ICartoonDuck>

這可以作爲:

std::vector<std::unique_ptr<ICartoonDuck>> cartoonDucks; 
cartoonDucks.push_back(makeUniqueCartoonDuck<Huey>()); 
cartoonDucks.push_back(makeUniqueCartoonDuck<Dewey>()); 
cartoonDucks.push_back(makeUniqueCartoonDuck<Louie>()); 

for (std::unique_ptr<ICartoonDuck> const& cd: cartoonDucks) { 
    cd->foo(); 
    cd->bar(); 
} 
+0

如果我理解正確'卡通鴨'將舉行'休伊''路易'等吧? –

+0

@Koushik:是的,這就是主意,讓我舉一個例子,顯然它不像我想象的那麼明顯。 –

+0

我喜歡這個解決方案,因爲它感覺就像C++的風格一樣。+ 1 –