题
我觉得像这样的已经被问过,但我无法找到它SO,我也不能找到任何关于谷歌有用。也许“协变”是不是我要找的字,但这个概念是非常相似的协变的函数的返回类型,所以我认为这可能是正确的。这是我想做的事,它给了我一个编译器错误:
class Base;
class Derived : public Base;
SmartPtr<Derived> d = new Derived;
SmartPtr<Base> b = d; // compiler error
假设这些类是完全充实......我觉得你的想法。它不能转换SmartPtr<Derived>
成SmartPtr<Base>
一些不明原因。我记得,这是C ++和许多其他语言正常,但在现阶段,我不记得为什么。
我根本问题是:什么是执行此任务的操作的最佳方式?目前,我拉指针移出SmartPtr
的,它明确地向上转型为基本类型,然后在相应类型的新SmartPtr
包装它(请注意,因为我们的本土SmartPtr
类使用侵入性的参考,这是不泄漏资源数数)。这是长而凌乱,尤其是当我再需要来包装SmartPtr
在另一个目标......任何快捷方式?
解决方案
两个拷贝构造和赋值运算符应当能够采取不同类型的的SmartPtr并尝试将指针从一个到另一个复制。如果类型不兼容,编译器会抱怨,如果他们是兼容的,你已经解决了你的问题。是这样的:
template<class Type> class SmartPtr
{
....
template<class OtherType> SmartPtr(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> copy constructor
template<class OtherType> SmartPtr<Type> &operator=(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> assignment operator
};
其他提示
和SmartPtr<Base>
是SmartPtr<Derived>
一个所述SmartPtr
模板的两个不同的实例。这些新的类不共享Base
和Derived
做继承。因此,你的问题。
什么是执行此任务的操作的最佳方式?
SmartPtr<Base> b = d;
不调用赋值运算符。这将调用拷贝构造函数(副本在大多数情况下省略掉),并是完全一样的,如果你写的:
SmartPtr<Base> b(d);
提供一种用于拷贝构造函数,需要一个SmartPtr<OtherType>
并执行它。这同样适用于赋值运算符。你会写出来,拷贝构造函数和OP =牢记的SmartPtr的语义。
模板是不协变,这是良好的;想像一下在以下情况:
vector<Apple*> va;
va.push_back(new Apple);
// Now, if templates were covariants, a vector<Apple*> could be
// cast to a vector<Fruit*>
vector<Fruit*> & vf = va;
vf.push_back(new Orange); // Bam, we just added an Orange among the Apples!
要达到什么样的你正在尝试做的智能指针类必须有一个模板化的构造,这需要无论是另一个智能指针或其他类型的指针。你可以看看的boost :: shared_ptr的,这正是这么做的。
template <typename T>
class SmartPointer {
T * ptr;
public:
SmartPointer(T * p) : ptr(p) {}
SmartPointer(const SmartPointer & sp) : ptr(sp.ptr) {}
template <typename U>
SmartPointer(U * p) : ptr(p) {}
template <typename U>
SmartPointer(const SmartPointer<U> & sp) : ptr(sp.ptr) {}
// Do the same for operator= (even though it's not used in your example)
};
还要看SmartPtr
类。如果有一个拷贝构造函数(或者你的情况,赋值运算符),其采用SmartPtr<T>
,其中T是用的话,就不会去上班构建的类型,因为SmartPtr<T1>
无关SmartPtr<T2>
即使T1和T2继承关系。
但是,如果的SmartPtr拥有的的模板化的拷贝构造函数/赋值运算符,用模板参数TOther
,接受SmartPtr<TOther>
,那么它应该工作。
假设你具有的SmartPtr类的控制下,该解决方案是提供一种模板构造函数:
template <class T>
class SmartPtr
{
T *ptr;
public:
// Note that this IS NOT a copy constructor, just another constructor that takes
// a similar looking class.
template <class O>
SmartPtr(const SmartPtr<O> &src)
{
ptr = src.GetPtr();
}
// And likewise with assignment operator.
};
如果在T和O型是兼容的,它会工作,如果他们是不是你会得到一个编译错误。
我认为最简单的事情是根据下面的到另一个的SmartPtr提供自动转换:
template <class T>
class SmartPtr
{
public:
SmartPtr(T *ptr) { t = ptr; }
operator T * () const { return t; }
template <class Q> operator SmartPtr<Q> () const
{ return SmartPtr<Q>(static_cast<Q *>(static_cast<T *>(* this))); }
private:
T *t;
};
请注意,此实现是在这个意义上稳健的转换操作模板并不需要了解智能指针的语义,所以引用计数并不需要复制等。