Чистый виртуальный вызов из конструктора и деструктора - PullRequest
16 голосов
/ 28 декабря 2011

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

Ответы [ 5 ]

19 голосов
/ 28 декабря 2011

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

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

5 голосов
/ 28 декабря 2011

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

4 голосов
/ 28 декабря 2011

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

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

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

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

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

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

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

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

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

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

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

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

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

2 голосов
/ 28 декабря 2011

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

0 голосов
/ 28 декабря 2011

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

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

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

...