这是我的尝试:
template<class T>
class Child : public T
{
public:
typedef T Parent;
};
template<typename _T>
class has_parent
{
private:
typedef char One;
typedef struct { char array[2]; } Two;
template<typename _C>
static One test(typename _C::Parent *);
template<typename _C>
static Two test(...);
public:
enum { value = (sizeof(test<_T>(nullptr)) == sizeof(One)) };
};
class A
{
public :
virtual void print() = 0;
};
class B : public Child<A>
{
public:
void print() override
{
printf("toto \n");
}
};
template<class T, bool hasParent = has_parent<T>::value>
class ICovariantSharedPtr;
template<class T>
class ICovariantSharedPtr<T, true> : public ICovariantSharedPtr<typename T::Parent>
{
public:
T * get() override = 0;
};
template<class T>
class ICovariantSharedPtr<T, false>
{
public:
virtual T * get() = 0;
};
template<class T>
class CovariantSharedPtr : public ICovariantSharedPtr<T>
{
public:
CovariantSharedPtr(){}
CovariantSharedPtr(std::shared_ptr<T> a_ptr) : m_ptr(std::move(a_ptr)){}
T * get() final
{
return m_ptr.get();
}
private:
std::shared_ptr<T> m_ptr;
};
还有一个例子:
class UseA
{
public:
virtual ICovariantSharedPtr<A> & GetPtr() = 0;
};
class UseB : public UseA
{
public:
CovariantSharedPtr<B> & GetPtr() final
{
return m_ptrB;
}
private:
CovariantSharedPtr<B> m_ptrB = std::make_shared<B>();
};
int _tmain(int argc, _TCHAR* argv[])
{
UseB b;
UseA & a = b;
a.GetPtr().get()->print();
}
说明:
此解决方案暗示了元编程,并修改了协变智能指针中使用的类。
简单的模板结构Child
在这里绑定类型Parent
和继承。从Child<T>
继承的任何类都将从继承T
并定义T
为Parent
。协变智能指针中使用的类需要定义此类型。
该类has_parent
用于在编译时检测是否定义了类型Parent
。这部分不是我的,我使用了与检测方法是否存在相同的代码(请参阅此处)
当我们希望与智能指针协方差时,我们希望我们的智能指针模仿现有的类体系结构。在示例中更容易解释它是如何工作的。
当一个CovariantSharedPtr<B>
被定义,它继承ICovariantSharedPtr<B>
,这被解释为ICovariantSharedPtr<B, has_parent<B>::value>
。正如B
所继承Child<A>
,has_parent<B>::value
是真实的,所以ICovariantSharedPtr<B>
是ICovariantSharedPtr<B, true>
和继承ICovariantSharedPtr<B::Parent>
是ICovariantSharedPtr<A>
。正如A
没有Parent
定义一样,它has_parent<A>::value
是假的,是假ICovariantSharedPtr<A>
的ICovariantSharedPtr<A, false>
并且是从无中继承的。
主要要点是B
继承自A
,我们ICovariantSharedPtr<B>
继承自ICovariantSharedPtr<A>
。因此,返回指针或引用on的任何方法ICovariantSharedPtr<A>
都可以通过返回on的方法而重载ICovariantSharedPtr<B>
。