Шаблонное возвращаемое значение C ++ с чисто виртуальной функцией - PullRequest
5 голосов
/ 17 мая 2011

У меня есть абстрактный класс Handle , который содержит ссылки на объекты типа T. Я хочу, чтобы этот класс можно было преобразовать в Handle , где U - суперкласс класса T. Iбудет использовать наследование, но это не работает здесь.Как бы я поступил так?Какие есть хорошие альтернативы?

Пример псевдо-кода:

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;
};

По запросу, это то, что я делаюсовместим с Handle, поэтому он может быть в корневом наборе CompatingPool.То же самое касается rootSet.Я начну эти специальные ручки, чтобы не было проблем с курицей и яйцом.

1 Ответ

4 голосов
/ 17 мая 2011
virtual template<class U> operator Handle<U>* () const  =0;

Виртуальная функция шаблона не разрешена спецификацией языка.

Рассмотрим этот код на ideone , а затем проследим ошибку компиляции:

ошибка: шаблоны не могут быть «виртуальными»


Что теперь вы можете сделать?Одним из решений является следующее:

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 является превосходным решением, так как вы определяетечерты производных классов без их редактирования.Кроме того, вы можете определить столько typedef, сколько захотите;скажем, ваш производный класс имеет более одной базы, вы можете определить множество typedef, или, предпочтительно, typelist .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...