2016-05-13 28 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)代码难以检查,因为问题仅在使用阶段才显现。

您的确有实例化它以查看所有错误。