如何告诉 C++ mixin 它实现的接口
How to tell a C++ mixin the interface it implements
我有一个接口和一个 class 实现它:
class InterfaceA
{
public:
enum Enum { X, Y, Z };
virtual void foo(Enum &) = 0;
virtual void bar() = 0;
};
class ClassA : public InterfaceA
{
public:
virtual void foo(Enum & a) {
a = X;
}
virtual void bar();
};
我需要在一个方面扩展实现 class 的 InterfaceA 的功能。据我了解,这就是 mixin 的用途。
例如foo() 应该在某些情况下更改其参数值。这是我的做法:
template <typename T>
class Mixin : public T
{
public:
virtual void foo(Enum & a) {
T::foo(a);
if (a == X){
a = Y;
}
}
};
问题是,它不会编译,除非我将作用域前缀写入接口 class 中定义的标识符,或者像这样对它们进行类型定义:
template <typename T>
class Mixin : public T
{
public:
typedef InterfaceA::Enum Enum;
virtual void foo(Enum & a) {
T::foo(a);
if (a == InterfaceA::X){
a = InterfaceA::Y;
}
}
};
如果来自接口定义的此类类型很少,这没什么大不了的。但如果有很多,它就会变得丑陋。我希望代码能够反映这样一个事实,即 Mixin 通过设计来操纵 InterfaceA 对象。不幸的是,从 InterfaceA 继承 Mixin 引入了 'dreaded diamond',我最好避免这种情况。这可能吗?
我想你应该使用虚拟继承;这应该可以避免 "dreaded diamond" 问题。
类似
class InterfaceA
{
public:
enum Enum { X, Y, Z };
virtual void foo(Enum &) = 0;
virtual void bar() = 0;
};
class ClassA : public virtual InterfaceA
{
public:
virtual void foo(Enum & a) {
a = X;
}
virtual void bar() {
}
};
template <typename T>
class Mixin : public T, public virtual InterfaceA
{
public:
virtual void foo(Enum & a) {
T::foo(a);
if (a == X){
a = Y;
}
}
};
int main ()
{
Mixin<ClassA> m;
return 0;
}
Enum
、X
和 Y
应该是依赖类型名。
您可以使用static_assert
强制继承。
template <typename T>
class Mixin : public T
{
public:
static_assert(std::is_base_of<InterfaceA, T>::value,
"T should inherit from InterfaceA");
virtual void foo(typename T::Enum & a) {
T::foo(a);
if (a == T::X){
a = T::Y;
}
}
};
我有一个接口和一个 class 实现它:
class InterfaceA
{
public:
enum Enum { X, Y, Z };
virtual void foo(Enum &) = 0;
virtual void bar() = 0;
};
class ClassA : public InterfaceA
{
public:
virtual void foo(Enum & a) {
a = X;
}
virtual void bar();
};
我需要在一个方面扩展实现 class 的 InterfaceA 的功能。据我了解,这就是 mixin 的用途。
例如foo() 应该在某些情况下更改其参数值。这是我的做法:
template <typename T>
class Mixin : public T
{
public:
virtual void foo(Enum & a) {
T::foo(a);
if (a == X){
a = Y;
}
}
};
问题是,它不会编译,除非我将作用域前缀写入接口 class 中定义的标识符,或者像这样对它们进行类型定义:
template <typename T>
class Mixin : public T
{
public:
typedef InterfaceA::Enum Enum;
virtual void foo(Enum & a) {
T::foo(a);
if (a == InterfaceA::X){
a = InterfaceA::Y;
}
}
};
如果来自接口定义的此类类型很少,这没什么大不了的。但如果有很多,它就会变得丑陋。我希望代码能够反映这样一个事实,即 Mixin 通过设计来操纵 InterfaceA 对象。不幸的是,从 InterfaceA 继承 Mixin 引入了 'dreaded diamond',我最好避免这种情况。这可能吗?
我想你应该使用虚拟继承;这应该可以避免 "dreaded diamond" 问题。
类似
class InterfaceA
{
public:
enum Enum { X, Y, Z };
virtual void foo(Enum &) = 0;
virtual void bar() = 0;
};
class ClassA : public virtual InterfaceA
{
public:
virtual void foo(Enum & a) {
a = X;
}
virtual void bar() {
}
};
template <typename T>
class Mixin : public T, public virtual InterfaceA
{
public:
virtual void foo(Enum & a) {
T::foo(a);
if (a == X){
a = Y;
}
}
};
int main ()
{
Mixin<ClassA> m;
return 0;
}
Enum
、X
和 Y
应该是依赖类型名。
您可以使用static_assert
强制继承。
template <typename T>
class Mixin : public T
{
public:
static_assert(std::is_base_of<InterfaceA, T>::value,
"T should inherit from InterfaceA");
virtual void foo(typename T::Enum & a) {
T::foo(a);
if (a == T::X){
a = T::Y;
}
}
};