Шаблоны C ++ и наследование - PullRequest
6 голосов
/ 24 ноября 2008

В моей платформе C ++ есть кнопки. Кнопка происходит от контроля. Таким образом, функция, принимающая элемент управления, может принять кнопку в качестве аргумента. Пока все хорошо.

У меня также есть список < T>. Однако List < Button> не является производным от List < Control>, что означает, что функция, принимающая список элементов управления, не может принимать список кнопок в качестве аргумента. Это прискорбно.

Может быть, это глупый вопрос, но я не вижу, как я могу решить это :( Список < Кнопка > должна происходить из Списка < Control >, но я не вижу способ сделать это "автоматически".

Ответы [ 5 ]

7 голосов
/ 24 ноября 2008

У Страуструпа есть пункт об этом в его FAQ:

Почему я не могу присвоить vector<Apple*> vector<Fruit*>

Вы можете решить это двумя способами:

  • Сделать список, содержащий указатели на Control. Тогда примите List<Control*>
  • Сделайте вашу функцию шаблоном. Вы все еще можете использовать List<Button> и List<Control> тогда, но это скорее стандартный код, и в большинстве случаев не обязательный.

Вот код для второго варианта. Первый вариант уже объясняется другими ответами:

class MyWindow {
    template<typename T>
    void doSomething(List<T> & l) {
        // do something with the list...
        if(boost::is_same<Control, T>::value) {
            // special casing Control

        } else if(boost::is_same<Button, T>::value) {
            // special casing Button

        }

    }
};

Чтобы ограничить doSomething только для List<derived from Control>, требуется еще немного кода (ищите enable_if, если хотите знать).

Обратите внимание, что такого рода код (смотря какой у вас тип) скорее избегать. Вы должны обрабатывать такие вещи с помощью виртуальных функций. Добавьте функцию doSomething в Control и переопределите ее в Button.

6 голосов
/ 24 ноября 2008

Я не хочу вам говорить, но если вы используете список экземпляров для Control вместо указателей на Control, ваши кнопки все равно будут мусором (Google "Object Slicing"). Если это списки указателей, то либо сделайте list<button*> в list<control*>, как предлагали другие, либо сделайте копию нового list<control*> из list<button*> и передайте , который в функция вместо Или переписать функцию как шаблон.

Итак, если раньше у вас была функция doSomething, которая принимала список элементов управления в качестве аргумента, вы бы переписали ее как:

template <class TControl>
void doSomething( const std::list<TControl*>& myControls ) {
  ... whatever the function is currently doing ...
}

void doSomethingElse() {
   std::list<Button*> buttons;
   std::list<Control*> controls;
   doSomething( buttons );
   doSomething( controls );
}
6 голосов
/ 24 ноября 2008

Как насчет использования указателей? Просто имейте список list<Control*> и поместите в него все объекты, производные от Control, которые вам нравятся.

2 голосов
/ 24 ноября 2008

Вместо использования List

0 голосов
/ 25 ноября 2008

Как правило, C ++ способ написания алгоритмов, выполняющих список, последовательность, ... состоит в предоставлении итераторов в качестве аргументов.

template < class iterator >
doSomething(iterator beg, iterator end);

Это решает, что List

По моему опыту, создание хороших шаблонизированных функций, работающих на итераторах, может быть большой (слишком большой) работой, но это "путь C ++" ...

Если вы идете по этому пути, рассмотрите возможность использования Boost.ConceptCheck . Это сделает вашу жизнь намного проще.

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