Философия дизайна C ++ заключается в том, что «вы не платите за то, что не используете». Возможно, вы уже знаете, что функция virtual
несет некоторые накладные расходы, поскольку класс должен поддерживать указатель на свою реализацию. Фактически, объект содержит ссылку на таблицу указателей функций, называемую vtable.
Рассмотрим следующий пример:
class Base
{
public:
virtual f() { /* do something */ }
};
class Derived : public Base
{
public:
virtual f() { /* do something */ }
};
Base* a = new Derived;
a->f(); // calls Derived::f()
Обратите внимание, что переменная a
указывает на объект Derived
. Поскольку f()
объявлено virtual
, таблица a
будет содержать указатель на Derived::f()
, и эта реализация будет выполнена. Если f()
не virtual
, vtable будет пустым. Таким образом, Base::f()
выполняется как тип a
, равный Base
.
Деструктор ведет себя так же, как и другие функции-члены. Если деструктор не virtual
, будет вызван только деструктор в классе Base
. Это может привести к утечке памяти / ресурсов, если класс Derived
реализует RAII . Если класс предназначен для подкласса, его деструктор должен быть virtual
.
В некоторых языках, таких как Java, все методы являются виртуальными. Таким образом, даже объекты, которые не предназначены для полиморфизации, будут использовать память для поддержки указателей на функции. Другими словами, вы вынуждены платить за то, что не используете.