Шаблоны C ++ с объектами интерфейса - PullRequest
7 голосов
/ 25 августа 2011

У меня есть следующий код, который не компилируется.

class Base {
    public:
        virtual ~Base() { };
};

class Derived : public Base { };

class NotDerived { };

template <typename T>
class Group { };

int main() {
    Group<Base> *g = NULL;

    g = new Group<Base>();       // Works
    g = new Group<Derived>();    // Error, but I want it to work

    g = new Group<NotDerived>(); // Error, as expected
}

Я понимаю, что это не скомпилируется, потому что g отличается от Group<Derived>.Чтобы сделать это в Java, я бы сделал что-то вроде Group<? extends Base> g, но, насколько мне известно, в C ++ этого ключевого слова нет.Что можно сделать?

Изменить: Я хотел бы уточнить, что я не хочу, чтобы можно было установить типы, не производные от Base, как g.Я обновил свой пример, чтобы объяснить это.

Редактировать 2: Есть два решения моей проблемы. Дейва Я обнаружил, что его просто и легко определить.Но Боуи (вместе с Марком дополнений) лучше соответствовал моим потребностям.

Ответы [ 6 ]

5 голосов
/ 25 августа 2011

Классы Group<Base> и Group<Derived> совершенно не связаны, разные классы.Указатели на них не могут быть преобразованы ни в одном направлении.

Если вам нужно полиморфное поведение во время выполнения, шаблон вашего класса Group может быть получен из общего (не шаблонного) базового класса:

class Group // base
{
   virtual ~Group() { }
};

template <typename T>
class ConcreteGroup : public Group
{
  // ...
  T * m_impl;
};

Group * g1 = new ConcreteGroup<A>;
Group * g1 = new ConcreteGroup<B>;
3 голосов
/ 25 августа 2011

Вы можете сделать группу базовым классом для всей группы T! = Base.

class Base {
    public:
        virtual ~Base() { };
};

class Derived : public Base { };


template <typename T> class Group;

struct Empty { };

template <typename T>
struct base_for_group_t {
    typedef Group<Base> type;
};

template <>
struct base_for_group_t<Base> {
    typedef Empty type;
};

template <typename T>
class Group : public base_for_group_t<T>::type { };

int main() {
    Group<Base> *g = 0;

    g = new Group<Base>();    // Works
    g = new Group<Derived>(); //  now works
}
2 голосов
/ 25 августа 2011

Ответ Боуи Оуэнса обрабатывает ковариацию, необходимую для решения исходного вопроса.Что касается ограничения, которое вы задали в редактируемом вопросе - вы можете достичь этого, используя черты типа.

template <typename T, class Enable = void> class Group;

template <typename T>
class Group<T, typename enable_if<is_base_of<Base, T>::value>::type> 
    : public base_for_group_t<T>::type { };
1 голос
/ 25 августа 2011

Я не думаю, что C ++ поддерживает это. Шаблон C ++ полностью обрабатывается во время компиляции, поэтому он не поддерживает полиморфизм . Это означает, что тип аргументов шаблона должен быть одинаковым для обеих сторон выражения присваивания.

0 голосов
/ 25 августа 2011

Мне кажется, я понимаю, для чего ты идешь. Я не уверен, что это лучший подход (и вы можете посмотреть на Boost.Factory ).

template <class T>
class Factory {

public:
  virtual T* operator()() = 0;
};

template <class Derived, class Base>
class ConcreteFactory : public Factory<Base> {

public:
  virtual Base* operator()() {
    return new Derived();
  }
};

class Base {
public:
  virtual ~Base() {};
};

class Derived1 : public Base { };
class Derived2: public Base {};

class NotDerived {};

int main()
{
  Factory<Base>* g;

  g = new ConcreteFactory<Derived1, Base>;
  g = new ConcreteFactory<Derived2, Base>;
  //  g = new ConcreteFactory<NotDerived, Base>; // Will not work if you try to do this
}
0 голосов
/ 25 августа 2011

Шаблоны c ++ и шаблоны java очень сильно отличаются друг от друга, например, квадрат и круг. один генерирует код, другой проверяет, что во время выполнения типы будут работать и совпадать в общем блоке кода. в двух словах.

В чем различия между "универсальными" типами в C ++ и Java?

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