C++模板化返回值与纯虚函数

5
我有一个抽象的Handle<T>类,它包含对类型为T的对象的引用。我希望能够将该类转换为Handle<U>,其中U是T的超类。我想使用继承,但在这里无法实现。我该如何做?有什么好的替代方案吗?
示例伪代码:
template<class T>
class Handle {
public:
    virtual ~Handle () {}
    virtual T & operator* () const = 0;
    virtual T * operator-> () const = 0;
    virtual template<class U> operator Handle<U>* () const = 0; // being lazy with dumb pointer
};

template<class T>
class ConcreteHandle : public Handle<T> {
public:
    explicit template<class U> ConcreteHandle (U * obj) : obj(obj) {}
    virtual ~ConcreteHandle () {}
    virtual T & operator* () const {
        return *obj;
    }
    virtual T * operator-> () const {
        return obj;
    }
    virtual template<class U> operator Handle<U>* () {
        return new ConcreteHandle<U>(obj);
    }
private:
    T * obj;
};

按照要求,这就是我正在做的事情。

class GcPool {
public:
    virtual void gc () = 0;
    virtual Handle<GcObject> * construct (GcClass clazz) = 0;
};

class CompactingPool : public GcPool {
public:
    virtual void gc () { ... }
    virtual Handle<GcObject> * construct (GcClass clazz) { ... }
private:
    Handle<GcList<Handle<GcObject> > > rootSet; // this will grow in the CompactingPool's own pool
    Handle<GcList<Handle<GcObject> > > knownHandles; // this will grow in the CompactingPool's own pool.
};

knownHandles需要与Handle兼容,以便它可以在CompatingPool的rootSet中。rootSet也是如此。我将引导这些特殊的句柄,以避免出现鸡生蛋的问题。


为什么不在基类中将operator Handle<U>()定义为具体实现呢?难道真的有必要提供不同的实现吗? - Tony Delroy
我的应用程序需要(读作:想要)各种类型的句柄。不同的内存(gc)池类型会产生不同的句柄。但我可能过度设计了。尽管如此,这对我来说仍然是一个有趣的问题。 - Thomas Eding
@Tony:这将使class Handle在其实现中使用其派生类。你可以这样做,但是假设实际上有多个可能从class Handle派生的类,那么这就没有意义了。如果没有,那么一开始就不应该有多态性。 - Keith
@trinithis:你考虑过使用模板参数而不是多态来管理分配器吗?请注意,它不必像STL分配器一样复杂。 - Keith
我正在编写一个编译器,并希望在语言中实现垃圾回收。我有一个抽象类GcPool。GcPool具有一个纯虚构造(Class)函数,该函数返回Handle<GcObject>。我正在更新GcPool的第一个实现CompactingPool,以在一些引导后内部使用句柄,以便它可以在自己的池中分配更多的句柄。但是我希望这些句柄具有比GcObject更好的类型,例如GcStack。也许这是显式转换的事情... - Thomas Eding
显示剩余4条评论
1个回答

4
virtual template<class U> operator Handle<U>* () const  =0;

模板虚函数不符合语言规范。

请参考这个ideone上的代码,然后查看编译错误:

错误:模板不能是“virtual”


现在你可以怎么做?一个解决方案是:

template<class T>
class Handle {
public:

    typedef typename T::super super; //U = super, which is a superclass of T.

    virtual ~Handle () {}
    virtual T & operator* () const = 0;
    virtual T * operator-> () const = 0;

    //not a template now, but still virtual
    virtual super operator Handle<super> () const = 0;  
};

也就是说,在派生类中定义一个基类的typedef,并在Handle中使用它。就像这样:
struct Base {//...};

struct Derived : Base { typedef Base super; //...};

Handle<Derived>  handle; 

或者你可以定义特征,例如:
struct Base {//... };

struct Derived : Base { //... };

template<typename T> struct super_traits;

struct super_traits<Derived>
{
   typedef Base super;
};

template<class T>
class Handle {
public:

    typedef typename super_traits<T>::super super; //note this now!

    virtual ~Handle () {}
    virtual T & operator* () const = 0;
    virtual T * operator-> () const = 0;

    //not a template now, but still virtual
    virtual super operator Handle<super> () const = 0; 
};

在我看来,super_traits是一种优秀的解决方案,因为您可以定义派生类的特性而无需编辑它们。此外,您可以定义任意数量的typedefs;比如说,如果您的派生类有多个基类,您可能希望定义许多typedefs,或者最好使用类型列表


1
@Nawaz,OP想要实现“虚拟模板”方法的效果。这就是为什么他提到了伪代码。可以假设他应该意识到错误。 - iammilind
@iammilind:由于虚拟模板不可行,所以现在已经不可能了。你不能定义虚拟模板。 - Nawaz
这是在重申已知的问题...问题中的代码表明了所需的功能 - Keith 知道它不起作用。他想要的是一些功能上等效的东西。 - Tony Delroy
2
@Nawaz,Tony 的意思是提问者想要一些模拟“虚拟模板”的功能。 - iammilind
@iammilind:这完全取决于“某些功能”的定义。你指的是什么?如果你说虚拟模板的“所有功能”,那就不含糊了,但“某些功能”就含糊不清了。顺便说一下,我只是试图解决这个问题。我不明白它为什么不能实现。 - Nawaz
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接