Как реализовать ковариацию класса шаблона в C ++? - PullRequest
2 голосов
/ 05 февраля 2011

Можно ли реализовать шаблон класса таким образом, чтобы один объект мог быть приведен к другому, если их аргументы шаблона связаны между собой? Вот пример, чтобы показать идею (конечно, она не скомпилируется):

struct Base {};
struct Derived : Base {};

template <typename T> class Foo {
    virtual ~Foo() {}
    virtual T* some_function() = 0;
};

Foo<Derived>* derived = ...;
Foo<Base>* base = derived;

Дополнительная проблема заключается в том, что Foo является абстрактным классом, используемым в качестве интерфейса, содержащего функции, возвращающие T & и T *, поэтому я не могу реализовать конструктор копирования шаблона.

Я пишу универсальный класс Iterator, который может содержать любой итератор STL, и в дополнение к стиранию типов я хотел бы, чтобы он был полиморфным, то есть я мог бы написать что-то вроде этого:

std::list<Derived> l;
MyIterator<Base> it(l.begin());

UPD: Это была моя ошибка, мне фактически не нужно было приводить Foo * к Foo * для реализации MyIterator, поэтому я думаю, что вопрос больше не актуален.

Ответы [ 3 ]

4 голосов
/ 05 февраля 2011

Хотя в других ответах указывалось, что такого рода отношения не являются «встроенными» в шаблоны, следует помнить, что можно создать функциональность для работы с такого рода отношениями.Например, boost::shared_dynamic_cast и друзья с учетом

class A { ... };
class B : public A { ... };

позволяют вам разыгрывать от boost::shared_ptr<A> до boost::shared_ptr<B>.

Обратите внимание, что если вы собираетесь реализовать что-то подобное, вам нужно быть осторожным с операциями, которые поддерживает MyIterator.Например, используя ваш пример MyIterator<Base>(std::list<Derived>::iterator), у вас не должно быть версии lvalue operator*(), например,

  *myIter = someBaseValue;

не должно компилироваться.

4 голосов
/ 05 февраля 2011

Аргумент шаблона не имеет ничего общего с содержимым объекта, на который вы указываете.Нет причин, по которым это должно работать.Чтобы проиллюстрировать

struct Base { };
struct Derived : Base {};

template<typename T> struct A { int foo; };
template<> struct A<Base> { int foo; int bar; };

A<Derived> a;
A<Base> *b = &a; // assume this would work
b->bar = 0; // oops!

Вы в конечном итоге получите доступ к целому числу bar, которое на самом деле не существует в a!


ОК, теперь, когда вы предоставили больше информацииЯсно, что вы хотите сделать что-то совершенно другое.Вот некоторый стартер:

template<typename T>
struct MyIterator : std::iterator<...> {
  MyIterator():ibase() { }
  template<typename U>
  MyIterator(U u):ibase(new Impl<U>(u)) { }
  MyIterator(MyIterator const& a):ibase(a.ibase->clone())

  MyIterator &operator=(MyIterator m) {
    m.ibase.swap(ibase);
    return *this;
  }

  MyIterator &operator++() { ibase->inc(); return *this; }
  MyIterator &operator--() { ibase->dec(); return *this; }
  T &operator*() { return ibase->deref(); }
  // ...

private:
  struct IBase { 
    virtual ~IBase() { }
    virtual T &deref() = 0; 
    virtual void inc() = 0;
    virtual void dec() = 0;
    // ...

    virtual IBase *clone() = 0;
  };
  template<typename U>
  struct Impl : IBase { 
    Impl(U u):u(u) { }
    virtual T &deref() { return *u; }
    virtual void inc() { ++u; }
    virtual void dec() { --u; }
    virtual IBase *clone() { return new Impl(*this); }
    U u;
  };

  boost::scoped_ptr<IBase> ibase;
};

Тогда вы можете использовать его как

MyIterator<Base> it(l.begin());
++it; 
Base &b = *it;

Возможно, вы захотите взглянуть на any_iterator.Если повезет, вы можете использовать этот шаблон для своих целей (я не проверял его).

1 голос
/ 05 февраля 2011

Foo<Derived> не наследует Foo<Base>, поэтому вы не можете преобразовать первое в второе.Кроме того, ваше предположение неверно: dynamic_cast не удастся.

Вы можете создать новый объект экземпляра Foo<Base>, который будет копировать ваш Foo<Derived> экземпляр, но я думаю, это то, что вы ищетедля.

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