Чистый виртуальный вызов из конструктора и деструктора - программирование
Подтвердить что ты не робот

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

В стандарте С++ говорится, что вызов чистой виртуальной функции из конструктора или деструктора запрещен. Что является причиной этого? Почему стандарт должен устанавливать такое ограничение?

4b9b3361

Ответ 1

В точке запуска выполняется деструктор класса, все деструкторы подкласса уже запущены. Неправильно было бы вызывать виртуальный метод, определенный подклассом, для которого уже запущен его деструктор.

Аналогичное ограничение существует при вызове виртуальных методов в конструкторах. Вы не можете вызвать виртуальный метод для подкласса, конструктор которого еще не запущен.

Ответ 2

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

Ответ 3

В стандарте С++ говорится, что вызов чистой виртуальной функции из конструктора или деструктора запрещен. Что является причиной этого? Почему стандарт должен устанавливать такое ограничение?

Из, по общему признанию, старого проекта стандарта С++, но соответствующие различия, которые я приведу, будут актуальны:

10.4-6 Функции-члены могут быть вызваны из конструктора (или деструктора) абстрактного класса; эффект виртуального вызова (class.virtual) на чистую виртуальную функцию, прямо или косвенно, для создаваемого (или уничтоженного) объекта из такого конструктора (или деструктора) составляет undefined.

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

undefined behaviour happens when an abstract class constructor or destructor calls one of its own member functions that is (still) pure virtual.

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

Класс является абстрактным, если он имеет хотя бы одну чистую виртуальную функцию. [Примечание: такая функция может быть унаследована: см. Ниже. ]

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

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

При таком понимании того, что undefined в Стандарте, мы можем вернуться к вашим вопросам: "В чем причина этого? Почему стандарт должен устанавливать такое ограничение?"

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

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

Типичная реализация механизма виртуальной диспетчеризации может представлять это, указав в таблице виртуальной диспетчеризации базовый класс, содержащий чистую виртуальную функцию, которая установлена ​​в 0, не инициализирована или указана на какую-либо функцию "повысить оповещение", По мере ввода последовательных слоев конструкторов производного класса указатель на таблицу виртуальной диспетчеризации будет перезаписан адресом их собственных VDT. Эти производные классы, переопределяющие реализацию, указывают на их собственную функцию defintion, которая станет дефолтом для любых более производных классов, которые сами не определяют новую реализацию. Этот критический неявный член-указатель-к-VDT будет перемещаться назад через этот же список VDT, когда деструкторы производного класса завершатся, гарантируя, что любые виртуальные вызовы будут выполняться на неструктурированных уровнях иерархии классов. Но, когда был создан деструктор для первого класса, в котором была определена виртуальная функция, будущие VDT снова не будут иметь ссылки на фактическую реализацию.

Ответ 4

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

Ответ 5

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

нет реализации функции, поэтому просто нет кода для вызова:)

подвыборы, реализующие чистый виртуальный, не существуют при вызове конструктора/деструктора.