2016-05-13 82 views
2

鑑於一些基本接口A,B,C ....Ñ如何實現多個接口的多態參數?

並實現一組其中的一些假設的類:

class MyClass1: public A, public B, public N; 
class MyClass2: public A, public B, public D; 

我想創建功能,其接受作爲參數的對象(或指針爲對象)的一類,其中包括,讓說A和B.

void myFunc(A&B obj); 

從一個C++程序員的角度來看,這似乎荒謬的。從軟件架構師的角度來看,這似乎是所有語言都應該具備的基本集團。

是否有任何技巧(模板除外)或解決方案?

注意:大多數接口不是來自我的,所以原則上不可能對接口進行更改。

編輯: 這裏是一些例子:

class A{ 
public: 
    virtual void draw()=0; 
}; 

class B{ 
public: 
    virtual void edit()=0; 
}; 


class AandB: public A, public B 
{ 
    virtual void draw()override{}; 
    virtual void edit()override{}; 
}; 

//This function know about A, B, but not AandB 
void some_function((A+B)& a_and_b) { // That do not work 
    a_and_b.draw(); 
    a_and_b.edit(); 
} 

int main() 
{ 
    AandB c; 
    some_function(c); // that is not so easy 
} 
+0

在我看來,'MyClass'繼承'A'和'B'這個事實與這個問題無關。 'A'和'B'是不相關的類型,所以真正的問題是如何編寫一個可以接受兩種不相關類型之一的函數。 – Galik

+0

@Galik:這是一個界面的要點:定義一些行爲。 A是一種行爲(可繪製?),B是另一種行爲(可編輯?)。所以這個函數接受任何可編輯和可繪製的類。所以你的問題的答案是:不是A或B,而是A和B. –

+0

啊好的。所以你想接受任何實現'A'和'B'的類。模板實際上是解決這個問題的方法,您爲什麼不想要模板解決方案? – Galik

回答

3

你真正要求的是編譯器創建一箇中間型(A & B),其接口包含兩個接口A接口B。然後允許任何類型實現這兩個這些接口綁定到這個組合類型的引用。

我什至不知道你怎麼可能是指這樣一種格式塔類型的語法:通過簡單地接受

void func((A+B)& var); // ??? 

那麼你可以用當前的語法類似的事情,而不需要編譯器創建幕後腳手架參數兩次這樣的:減輕模板的利弊

struct A { void stuff(){ std::cout << "A\n"; } }; 
struct B { void stuff(){ std::cout << "B\n"; } }; 
struct C { void stuff(){ std::cout << "C\n"; } }; 

struct MyType: A, B, C 
{ 
    void stuff() { std::cout << "MyType\n"; } 
}; 

void func(A& a, B& b) // accept both interfaces in func 
{ 
    a.stuff(); // use interface A 
    b.stuff(); // use interface B 
} 

int main() 
{ 
    MyType m; 

    func(m, m); // pass both interfaces to func() 
} 
+1

很聰明。複製參數有點混亂,但仍然是一個不錯的主意。 –

+1

非常聰明:)那麼模板函數呢,接受單個參數,並傳遞給func?例如像'template func2(T&a){return func(a,a); }' – Nick

4
#include <type_traits> 

using namespace std; 

class A{}; 
class B{}; 

template<class T, enable_if_t<is_same<A, decay_t<T>>::value || is_same<B, decay_t<T>>::value, int> = 0> 
void some_function(T&& a_or_b) {} 

直播:https://godbolt.org/g/Z1MV8w

這個例子需要C++ 14,但如果你需要11的兼容性,可以使用enable_if代替。它只是不可讀。

如果你想採取任何從A或B繼承,使用is_base_of代替is_same

+0

我目前正在嘗試將此解決方案適用於我的案例,我將盡快接受或進一步發表評論。 –

+0

至少需要衰減'T'。 'is_base_of'也是一個有點可疑的檢查。 –

+0

用decay_t更新。你爲什麼說這是值得懷疑的?對於更細緻的TMP細節,我仍然很新。 – xaxxon

1

我投上xaxxon答案,
但F你想這樣做的「虛擬」的方式,
你可以做延伸AB的課程。

看起來就像這樣:

class A; 
class B; 
class A_B: public A, public B{ 
}; 

class MyClass1: public A_B, public XXX{ 
}; 

class MyClass2: public A_B, public YYY{ 
}; 

void myFunc(A_B obj); 

我同意這個看上去非常像Java的。

+1

在這種情況下,A_B應該從A和B幾乎繼承嗎?如果XXX或YYY繼承自A或B? – xaxxon

+0

感謝沒有模板的嘗試。但實際上這是不可能的: - 要求更改MyClass1和Myclass2 - 使用多於2個接口時,它變得瘋狂。 –

+0

如果有'A_B','A_XXX','B_XXX'等等,會有問題。 – Jarod42

1

一種方式

void myFunc_impl(A& aPart, B& bPart); // aPart and bPart are from the same object. 

template <typename T> 
void myFunc(T& obj) { 
    // static_assert to have better error messages 
    static_assert(std::is_base_of<A, T>::value, "T should inherit from A"); 
    static_assert(std::is_base_of<B, T>::value, "T should inherit from B"); 
    // Forwarding to implementation 
    myFunc_impl(obj, obj); 
} 

1)力的定義是在頭部,難以維持

你只需要轉發的標題: 碼短。

2)難以與多態指針來管理,

只要你需要引用或指針,這部分如果正常使用的模板。

4)它使困難或不可能的一些其他功能,如虛擬?

事實上,模板方法不能是模板,但在這裏,您可能會轉發到一個虛擬方法。

5)代碼難以檢查,因爲問題僅在使用階段才顯現。

您的確有實例化它以查看所有錯誤。