Является ли наследование от базового класса без виртуальных методов плохой практикой? - PullRequest
9 голосов
/ 09 августа 2011

Некоторое время назад я прочитал ответ на вопрос, касающийся dynamic_cast. Не удалось сработать dynamic_cast, поскольку в базовом классе не было виртуальных методов. В одном из ответов говорилось, что вывод из классов без виртуальных методов обычно означает плохой дизайн. Это правильно? Даже не пользуясь полиморфизмом, я все равно не вижу в этом неправильности.

Ответы [ 5 ]

7 голосов
/ 09 августа 2011

Это зависит от того, о чем мы говорим:

  • для классов черт (нет данных) все нормально (std::unary_function приходит на ум)
  • для private наследования (используется вместо композиции для извлечения выгоды из пустой базовой оптимизации), тоже хорошо

Проблема возникает, когда вы начинаете обрабатывать такой производный объект полиморфно по отношению к этому базовому классу. Если вы когда-нибудь достигнете такой позиции, тогда это определённый кодовый запах .

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

2 голосов
/ 09 августа 2011

Извлечение из класса всегда допустимый параметр для повторного использования кода.

Иногда мы не ищем полиморфное поведение.Это нормально - есть причина, по которой у нас есть такая возможность.Однако если это так, тогда рассмотрите возможность использования частного наследования - если ваш класс не должен быть полиморфным, тогда ни у кого нет причин пытаться использовать его полиморфно.

1 голос
/ 09 августа 2011

Вот хороший пример для включения поведения в политики (обратите внимание на защищенный деструктор):

struct some_policy
{
    // Some non-virtual interface here
protected:
    ~some_policy() { ... }

private:
    // Some state here
};

struct some_class : some_policy, some_other_policy { ... };

Еще один хороший пример, чтобы избежать раздувания кода в шаблонах. Обратите внимание на защищенный деструктор:

struct base_vector
{
    // Put everything which doesn't depend 
    // on a template parameter here

protected:
    ~base_vector() { ... }
};

template <typename T>
struct vector : base_vector
{ ... };

Другой пример, называется CRTP. Обратите внимание на защищенный деструктор:

template <typename Base>
struct some_concept 
{
    void do_something { static_cast<Base*>(this)->do_some_other_thing(); }

protected:
    ~some_concept() { ... }
};

struct some_class : some_concept<some_class> { ... };

Другой пример, называется Оптимизация пустой базы. На самом деле не наследование, так как это больше хитрость, позволяющая компилятору не резервировать пространство в some_class для базового класса (который действует как закрытый член).

template <typename T>
struct some_state_which_can_be_empty { ... };

template <typename T>
struct some_class : private some_state_which_can_be_empty<T> { ... };

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

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

Некоторые классы в стандартной библиотеке C ++ имеют защищенные члены (которые имеют значение только для производного класса), но не имеют функций виртуальных членов.Т.е. они предназначены для деривации, без виртуалов.Это доказывает, что, как правило, плохой дизайн должен происходить из класса без виртуалов.

Cheers & hth.,

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

Наследование без виртуальных методов в C ++ - это не что иное, как повторное использование кода. Я не могу думать о наследовании без полиморфизма.

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