C ++: Почему struct \ class нужен виртуальный метод для того, чтобы быть полиморфным? - PullRequest
13 голосов
/ 29 апреля 2011

После этого вопроса , мне интересно, почему struct \ class в C ++ должен иметь виртуальный метод, чтобы быть полиморфным.

Форсировать виртуальный деструктор имеет смысл, но если деструктора нет вообще, почему обязательно иметь виртуальный метод?

Ответы [ 8 ]

19 голосов
/ 29 апреля 2011

Поскольку тип полиморфного объекта в C ++, в основном, определяется по указателю на его vtable, который является таблицей виртуальных функций. Однако vtable создается только при наличии хотя бы одного виртуального метода. Зачем? Потому что в C ++ вы никогда не получите то, что явно не просили. Они называют это «вам не нужно платить за то, что вам не нужно». Не нужен полиморфизм? Вы только что сохранили vtable.

8 голосов
/ 29 апреля 2011

Форсировать виртуальный деструктор имеет смысл

Точно. Чтобы уничтожить виртуальный класс вручную (через delete) через его базовый класс, вам потребуется виртуальный деструктор. (Теперь, как мне напомнили в комментариях, это обычно не требуется: вместо ручного управления памятью следует полагаться на современные интеллектуальные указатели, которые также корректно работают с не виртуальными деструкторами.)

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

И поскольку полиморфизм во время выполнения добавляет издержки (класс должен хранить дополнительный указатель на свою таблицу виртуальных методов), по умолчанию он не добавляется, если это не требуется в любом случае: философия проектирования C ++ заключается в «Вы платите только за то, что вам нужно». Создание для каждого класса таблицы виртуальных методов противоречит этому принципу.

3 голосов
/ 29 апреля 2011

Поскольку оно определено как таковое в стандарте.

От 10,3 / 1 [class.virtual]

Виртуальные функции поддерживают динамическое связывание и объектно-ориентированное программирование. Класс, который объявляет или наследует виртуальную функцию, называется полиморфным классом.

Имеет смысл, что если вы используете наследование, то у вас есть хотя бы один виртуальный метод. Если у вас нет виртуального метода, вы можете вместо этого использовать композицию.

2 голосов
/ 29 апреля 2011

Мне интересно, почему struct \ class в C ++ должен иметь виртуальный метод, чтобы быть полиморфным?

Потому что это то, что означает полиморфный класс.

В C ++ полиморфизм во время выполнения достигается с помощью виртуальных функций. Базовый класс объявляет некоторые виртуальные функции, которые реализуют многие производные классы, и клиенты используют указатели (или ссылки) статического типа базового класса и могут заставить их указывать на объекты производных классов (часто различных производных классов) и затем Назовите реализацию производных классов через базовые указатели. Вот как достигается полиморфизм во время выполнения. А поскольку центральную роль играют функции virtual, которые обеспечивают полиморфизм во время выполнения, поэтому классы, имеющие виртуальные функции, называются полиморфными классами.

2 голосов
/ 29 апреля 2011
Полиморфизм

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

1 голос
/ 29 апреля 2011

Философия дизайна 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, все методы являются виртуальными. Таким образом, даже объекты, которые не предназначены для полиморфизации, будут использовать память для поддержки указателей на функции. Другими словами, вы вынуждены платить за то, что не используете.

1 голос
/ 29 апреля 2011

Без какого-либо виртуального метода нет необходимости поддерживать виртуальный указатель (сокращенно vptr) для каждого объекта класса.Виртуальный указатель - это механизм разрешения вызовов виртуальных методов во время выполнения;в зависимости от класса объекта, он может указывать на различные таблицы виртуальных методов (сокращенно vtable), которые содержат фактические адреса виртуальных методов.

Таким образом, проверяя, к какой vtable относится точка vptrto, компилятор может определить класс объекта, например, в dynamic_cast.Тип объекта без vptr не может быть определен таким образом и не является полиморфным.

0 голосов
/ 29 апреля 2011

Классы нуждаются только в виртуальных методах, чтобы быть динамически полиморфными - по причинам, описанным другими. Тем не менее, вы можете иметь статический полиморфизм через шаблоны.

...