C++中接口的多重继承
Multiple inheritance of interfaces in C++
我有一个对象接口和一个派生对象可能想要支持的开放端接口集合。
// An object
class IObject
{
getAttribute() = 0
}
// A mutable object
class IMutable
{
setAttribute() = 0
}
// A lockable object
class ILockable
{
lock() = 0
}
// A certifiable object
class ICertifiable
{
setCertification() = 0
getCertification() = 0
}
一些派生对象可能如下所示:
class Object1 : public IObject, public IMutable, public ILockable {}
class Object2 : public IObject, public ILockable, public ICertifiable {}
class Object3 : public IObject {}
我的问题是:有没有一种方法可以编写只接受这些接口的某些组合的函数?例如:
void doSomething(magic_interface_combiner<IObject, IMutable, ILockable> object);
doSomething( Object1() ) // OK, all interfaces are available.
doSomething( Object2() ) // Compilation Failure, missing IMutable.
doSomething( Object3() ) // Compilation Failure, missing IMutable and ILockable.
我发现的最接近的东西是boost::mpl::inherit。我取得了一些有限的成功,但这并不能完全满足我的需要。
例如:
class Object1 : public boost::mpl::inherit<IObject, IMutable, ILockable>::type
class Object2 : public boost::mpl::inherit<IObject, ILockable, ICertifiable>::type
class Object3 : public IObject
void doSomething(boost::mpl::inherit<IObject, ILockable>::type object);
doSomething( Object1() ) // Fails even though Object1 derives from IObject and ILockable.
doSomething( Object2() ) // Fails even though Object2 derives from IObject and ILockable.
我认为类似于boost::mpl::inherit的东西可能会起作用,但这会生成一个具有所提供类型的所有可能排列的继承树。
我也对解决这个问题的其他方法感到好奇。理想情况下,它可以进行编译时检查,而不是运行时检查(即没有dynamic_cast)。
您可以使用递归可变继承编写接口检查类:
template<typename... Interfaces>
struct check_interfaces;
template<>
struct check_interfaces<> {
template<typename T> check_interfaces(T *) {}
};
template<typename Interface, typename... Interfaces>
struct check_interfaces<Interface, Interfaces...>:
public check_interfaces<Interfaces...> {
template<typename T> check_interfaces(T *t):
check_interfaces<Interfaces...>(t), i(t) {}
Interface *i;
operator Interface *() const { return i; }
};
例如:
struct IObject { virtual int getAttribute() = 0; };
struct IMutable { virtual void setAttribute(int) = 0; };
struct ILockable { virtual void lock() = 0; };
void f(check_interfaces<IObject, IMutable> o) {
static_cast<IObject *>(o)->getAttribute();
static_cast<IMutable *>(o)->setAttribute(99);
}
struct MutableObject: IObject, IMutable {
int getAttribute() { return 0; }
void setAttribute(int) {}
};
struct LockableObject: IObject, ILockable {
int getAttribute() { return 0; }
void lock() {}
};
int main() {
f(new MutableObject);
f(new LockableObject); // fails
}
注意,check_interfaces
具有每个检查接口一个指针的占用空间;这是因为它对实际参数的声明类型执行类型擦除。
您应该使用static_assert
来检查函数中的类型:
#include <type_traits>
template< typename T >
void doSomething( const T& t )
{
static_assert( std::is_base_of<IObject,T>::value, "T does not satisfy IObject" );
static_assert( std::is_base_of<IMutable,T>::value, "T does not satisfy IMutable" );
// ...
}
这将给您非常好的错误消息,告诉您哪些接口不满意。如果您需要重载该功能,并且有一个仅适用于特定接口组合的版本,您也可以使用enable_if
:
#include <type_traits>
template< typename T, typename... Is >
struct HasInterfaces;
template< typename T >
struct HasInterfaces< T > : std::true_type {};
template< typename T, typename I, typename... Is >
struct HasInterfaces< T, I, Is... >
: std::integral_constant< bool,
std::is_base_of< I, T >::value && HasInterfaces< T, Is... >::value > {};
template< typename T >
typename std::enable_if< HasInterfaces< T, IObject, IMutable >::value >::type
doSomething( const T& t )
{
// ...
}
当不满足接口要求时,这将使函数从过载集中消失。
使用std::enable_if
和std::is_base_of
:的解决方案
#include <type_traits>
// An object
struct IObject
{
virtual void getAttribute() = 0;
};
// A mutable object
struct IMutable
{
virtual void setAttribute() = 0;
};
// A lockable object
struct ILockable
{
virtual void lock() = 0;
};
// A certifiable object
struct ICertifiable
{
virtual void setCertification() = 0;
virtual void getCertification() = 0;
};
struct Object1 : public IObject, public IMutable, public ILockable
{
void getAttribute() {}
void setAttribute() {}
void lock() {}
};
struct Object2 : public IObject, public ILockable, public ICertifiable
{
void getAttribute() {}
void lock() {}
void setCertification() {}
void getCertification() {}
};
struct Object3 : public IObject
{
void getAttribute() {}
};
template<typename T>
void doSomething(
typename std::enable_if<
std::is_base_of<IObject, T>::value &&
std::is_base_of<IMutable, T>::value &&
std::is_base_of<ILockable, T>::value,
T>::type& obj)
{
}
int main()
{
Object1 object1;
Object2 object2;
Object3 object3;
doSomething<Object1>(object1); // Works
doSomething<Object2>(object2); // Compilation error
doSomething<Object3>(object3); // Compilation error
}
也许这不是最优雅的方式,因为它是用C++03语法完成的
template <typename T, typename TInterface>
void interface_checker(T& t)
{
TInterface& tIfClassImplementsInterface = static_cast<TInterface&>(t);
}
这是给你的精神的把戏。现在以您为例:
template <typename T, typename TInterface1, typename TInterface2, typename TInterface3 >
void magic_interface_combiner(T& t)
{
TInterface1& tIfClassImplementsInterface = static_cast<TInterface1&>(t);
TInterface2& tIfClassImplementsInterface = static_cast<TInterface2&>(t);
TInterface3& tIfClassImplementsInterface = static_cast<TInterface3&>(t);
}
我想使用C++11类型的特性可以做得更聪明。
只想让您尝一尝C++11:
无递归的单一类型:
template <typename... Ts>
class magic_interface_combiner {
typedef std::tuple<Ts*...> Tpl;
Tpl tpl;
template <typename T, int I>
T *as_(std::false_type)
{
static_assert(I < std::tuple_size<Tpl>::value, "T not found");
return as_<T, I+1>(std::is_same<T, typename std::tuple_element<I+1, Tpl>::type>{});
}
template <typename T, int I>
T *as_(std::true_type) { return std::get<I>(tpl); }
public:
template <typename T>
magic_interface_combiner(T * t) : tpl(static_cast<Ts*>(t)...) {}
template <typename T> T * as() { return as_<T, 0>(std::false_type{}); }
};
// no template
void doSomething(magic_interface_combiner<IObject, IMutable, ILockable> object)
{
}
两种类型但没有递归:
template <typename T>
class single_interface_combiner {
T *p;
public:
single_interface_combiner(T *t) : p(t) {}
operator T* () { return p; }
};
template <typename... Ts>
struct magic_interface_combiner : single_interface_combiner<Ts>... {
template <typename T>
magic_interface_combiner(T* t) : single_interface_combiner<Ts>(t)... {}
template <typename T>
T * as() { return *this; }
};
相关文章:
- 关于C++中具有多重继承"this"指针的说明
- C++中模板化异常类的多重继承
- 虚拟继承中是否存在多重继承?
- 如何在 c++ 多重继承中调用父非虚函数?
- 多重继承相同的方法名,没有歧义
- 使用enable_if解决多重继承歧义
- 多重继承导致虚假的模糊虚拟函数过载
- 多重继承和访问不明确的元素
- C++ 多重继承:使用基类 A 的实现实现基类 B 的抽象方法
- 关于C 接口(纯虚拟类)/多重继承/虚拟继承的设计Qustion
- C++ 从接口和强制转换的多重继承
- 模板、接口(多重继承)和静态函数(命名构造函数)
- 是否有可能用Java接口取代C++的多重继承
- c++中带接口的多重继承
- 从未知的派生类调用接口函数(多重继承)
- C++中接口的多重继承
- 从接口的 C++ 模板多重继承
- 来自接口(抽象类)的多重继承
- 处理接口多重继承的方法
- c++中的接口,没有多重继承