这是我的尝试:
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 类型。这部分不是我的,我使用了相同的代码来检测方法是否存在(see here)
由于我们想要与智能指针的协方差,我们希望我们的智能指针模仿现有的类架构。在示例中更容易解释它是如何工作的。
当一个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>,并且从无继承。
重点是Binherits from A,我们有ICovariantSharedPtr<B>inheriting from ICovariantSharedPtr<A>。因此,任何在ICovariantSharedPtr<A> 上返回指针或引用的方法都可以被在ICovariantSharedPtr<B> 上返回相同的方法重载。