这是我的尝试:
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
。这部分不是我的,我使用了与检测方法是否存在相同的代码(请参见此处)
由于我们想要与智能指针的协变,我们希望我们的智能指针模仿现有的类架构。在示例中更容易解释它是如何工作的。
当 aCovariantSharedPtr<B>
被定义时,它继承自ICovariantSharedPtr<B>
,它被解释为ICovariantSharedPtr<B, has_parent<B>::value>
。AsB
继承自Child<A>
,has_parent<B>::value
是真的,所以ICovariantSharedPtr<B>
isICovariantSharedPtr<B, true>
并且继承自ICovariantSharedPtr<B::Parent>
which is ICovariantSharedPtr<A>
。AsA
没有Parent
定义,has_parent<A>::value
是假的,ICovariantSharedPtr<A>
是ICovariantSharedPtr<A, false>
并且从无继承。
重点是作为B
继承自A
,我们有ICovariantSharedPtr<B>
继承自ICovariantSharedPtr<A>
。因此,任何返回指针或引用 onICovariantSharedPtr<A>
的方法都可以被返回相同 on 的方法重载ICovariantSharedPtr<B>
。