Чем перегрузка виртуального метода отличается от не виртуального метода?

в чем разница между этими двумя:

  • объявление функции базового класса виртуальной и изменение производного класса функция.
  • перегрузка унаследованной не виртуальной функции.

когда следует использовать один над другим?

3 ответов


когда у вас есть метод базового класса объявлен как virtual, чтобы переопределить его, вам нужно предоставить функцию с точно такой же сигнатурой в производном классе (типы возврата Co-variant разрешено, хотя).

если ваше имя функции такое же, но подпись в производном классе варьируется от одного в базовом классе, чем она больше не переопределяется, это


перегрузка полностью отделена от (ортогональной) виртуальной переопределение.

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

при перегрузке, функция подписи с различными типами аргументов одновременно выступают в качестве кандидатов, которые будут выбраны при вызове функции. Существует невероятно сложный набор правил, чтобы выбрать правильный, который работает хорошо 95% времени и дает вам головную боль, когда он не сотрудничает.

поскольку перегрузка работает с разными сигнатурами, а переопределение работает с одинаковыми сигнатурами, они действительно не мешают друг другу.

вы можете явно импортировать функции базы класс в производный класс для расширения имени перегруженной функции. Это делается using base_class::overload_name; внутри производного класса.


Я считаю, что вы имели в виду переопределение не виртуальных функций и не перегрузку. При переопределении функции не виртуального базового класса в производном классе вызов функции разрешается и привязывается во время компиляции. Это означает, что вызов функции разрешен на основе типа (или указателя), на котором вызывается функция. Если вы вызываете функцию на указателе базового класса, то версия базового класса вызывается всегда. Если вы используете указатель производного класса производная версия вызывается всегда; независимо от фактического объекта, на который она указывает.

Если версия базового класса помечена как виртуальная, то разрешение вызова или привязка откладывается для выполнения во время выполнения на основе типа объекта, на котором выполняется вызов, а не на основе типа указателя, используемого для выполнения вызова. Это означает, что можно использовать указатель базового класса для указания на объекты базового и производного классов, а затем вызвать функцию. На основе типа объекта указатель указывает на, вызывается соответствующая версия функции. Это означает, что если мой указатель указывает на объект базового класса, то вызывается версия базового класса. Если указатель указывает на объект производного типа, вызывается производный verion.