C++协变模板

rme*_*dor 17 c++ templates covariance

我觉得之前已经问过这个问题,但我无法在SO上找到它,也无法在Google上找到任何有用的信息.也许"covariant"不是我正在寻找的词,但这个概念与函数的协变返回类型非常相似,所以我认为它可能是正确的.这是我想要做的,它给了我一个编译器错误:

class Base;
class Derived : public Base;

SmartPtr<Derived> d = new Derived;
SmartPtr<Base> b = d; // compiler error
Run Code Online (Sandbox Code Playgroud)

假设这些课程充分充实......我想你明白了.它不能转换SmartPtr<Derived>SmartPtr<Base>某种不明原因.我记得在C++和许多其他语言中这是正常的,虽然目前我不记得为什么.

我的根本问题是:执行此赋值操作的最佳方法是什么?目前,我正在将指针拉出,将其SmartPtr明确地向上转换为基类型,然后将其包装为新SmartPtr的适当类型(请注意,这不会泄漏资源,因为我们的本地SmartPtr类使用侵入式引用计数).那是漫长而凌乱的,尤其是当我需要将SmartPtr另一个对象包裹起来时...任何快捷方式?

dir*_*tly 15

SmartPtr<Base>并且SmartPtr<Derived>SmartPtr模板的两个不同的实例.这些新类不共享的继承问题BaseDerived做的.因此,你的问题.

执行此赋值操作的最佳方法是什么?

 SmartPtr<Base> b = d; 
Run Code Online (Sandbox Code Playgroud)

不调用赋值运算符.这会调用copy-ctor(大多数情况下都会删除副本),就像你写的那样:

 SmartPtr<Base> b(d); 
Run Code Online (Sandbox Code Playgroud)

提供需要SmartPtr<OtherType>并实现它的复制者.赋值运算符也是如此.你必须写出copy-ctor和op =记住SmartPtr的语义.

  • 很大程度上取决于SmartPtr类的确切语义,例如它是否具有所有权转移,是否进行引用计数等.您必须写出copy-ctor和op =记住SmartPtr的语义. (2认同)

MSN*_*MSN 12

复制构造函数和赋值运算符都应该能够采用不同类型的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
};
Run Code Online (Sandbox Code Playgroud)


Luc*_*lle 5

模板不是协变的,这很好; 想象在下列情况下会发生什么:

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!
Run Code Online (Sandbox Code Playgroud)

要实现您要执行的操作,SmartPointer类必须具有模板化构造函数,该构造函数可以使用另一个SmartPointer或另一个类型的指针.你可以看一下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)
};
Run Code Online (Sandbox Code Playgroud)

  • 我认为你的例子是一个错误的例子,因为它实际上并不完全是协变的_因为你可以在列表中推送像Orange这样的东西.如果公共接口只是_returns_ Fruit*,而不是_accepts_ Fruit*,它只会是协变的.C#提供"in"和"out"关键字,分别使泛型类型变为协变或逆变.它静态地强制使用类型来避免您描述的情况. (4认同)