如何为多个接口实现一个多态参数?
How to implement a polymorphic parameter to several interfaces?
给定一些基本接口 A、B、C.... N
还有一些假设的 classes 实现了其中的一组:
class MyClass1: public A, public B, public N;
class MyClass2: public A, public B, public D;
我想创建一个函数,它接受一个对象(或指向对象的指针)作为参数 class 其中包括,比方说 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
}
#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
我对 xaxxon 的回答投了票,
但如果您想以 "virtual" 方式进行,
你可以做 class 扩展 A
和 B
.
看起来像这样:
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。
您真正要求的是编译器创建一个中间类型(A
& B
),其接口包含 interface A
和 接口 B
。然后允许任何实现 both 这些接口的类型绑定到这个组合类型的引用。
我什至不确定您如何在语法中引用这样的格式塔类型:
void func((A+B)& var); // ???
好吧,您可以使用当前语法做类似的事情,而无需编译器在幕后创建脚手架,只需接受参数 twice,如下所示:
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()
}
减轻模板缺点的一种方法
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) force definition to be in the header, difficult to maintain
您刚刚在 header 中转发:
代码很短。
2) difficult to manage with polymorphic pointers,
只要你引用或指针,这部分就可以用模板。
4) It make difficult or impossible some other features like virtual?
的确,模板方法不能是模板,但是这里,你可以转发到虚方法。
5) Code is difficult to check, as issues are apparent only at usage stage.
您确实必须实例化它才能看到所有错误。
给定一些基本接口 A、B、C.... N
还有一些假设的 classes 实现了其中的一组:
class MyClass1: public A, public B, public N;
class MyClass2: public A, public B, public D;
我想创建一个函数,它接受一个对象(或指向对象的指针)作为参数 class 其中包括,比方说 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
}
#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
我对 xaxxon 的回答投了票,
但如果您想以 "virtual" 方式进行,
你可以做 class 扩展 A
和 B
.
看起来像这样:
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。
您真正要求的是编译器创建一个中间类型(A
& B
),其接口包含 interface A
和 接口 B
。然后允许任何实现 both 这些接口的类型绑定到这个组合类型的引用。
我什至不确定您如何在语法中引用这样的格式塔类型:
void func((A+B)& var); // ???
好吧,您可以使用当前语法做类似的事情,而无需编译器在幕后创建脚手架,只需接受参数 twice,如下所示:
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()
}
减轻模板缺点的一种方法
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) force definition to be in the header, difficult to maintain
您刚刚在 header 中转发: 代码很短。
2) difficult to manage with polymorphic pointers,
只要你引用或指针,这部分就可以用模板。
4) It make difficult or impossible some other features like virtual?
的确,模板方法不能是模板,但是这里,你可以转发到虚方法。
5) Code is difficult to check, as issues are apparent only at usage stage.
您确实必须实例化它才能看到所有错误。