C ++ дочерний конструктор и VPTR

0

Во многих источниках книги и т.д. Написаны "не вызывайте this-> virtualFunction в конструкторе дочернего класса", и в некоторых источниках объясните, почему вы не должны этого делать. Потому что на момент строительства класс вообще не создан. Таким образом, виртуальная функция, которая будет вызываться из дочернего конструктора, будет функцией базового класса. Это означает, что в блоке конструктора child VPTR этого класса указывается на базу VTABLE.

Поэтому мой вопрос:
каков момент в построении объекта, когда VPTR дочернего класса будет переопределен для обращения к нему виртуальной таблицы? Я предполагаю, что какой-то автоматически сгенерированный код сделает это в конце тела конструктора или после того, как будет обработан тело конструктора.

И второй вопрос:
почему VPTR переоценивается в конце строительства? Может быть, у него есть некоторые важные причины? Почему не удается переопределить VPTR в начале тела конструктора или после создания базового класса?

Child::Child() :
Base()
//<----- Why not here?
//members initialization
{
//<----- Why not here?
//code
}
  • 1
    Нет, в теле конструктора Child динамический тип - это Child , а не Base . Это Base в конструкторе Base . (Я не совсем уверен, изменится ли он до или после инициализации Child элементов, поэтому я не могу дать полный ответ).
Показать ещё 2 комментария
Теги:
constructor
parent-child
vtable
vptr

2 ответа

1
Лучший ответ

Во многих источниках книги и т.д. Написаны "не вызывайте this-> virtualFunction в конструкторе дочернего класса"

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

Внутри конструктора производного класса они четко определены и делают то, что вы ожидаете.

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

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

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

После того, как все конструкторы базового класса завершены, и до того, как инициализируются дочерние классы. Функции Child элементов, включая виртуальные функции, можно вызывать из инициализаторов-членов (но не для инициализаторов базового класса) или тела конструктора.

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

почему VPTR переоценивается в конце строительства?

Это не так. Это происходит в первом пункте, который вы указываете с помощью <----- Why not here? ,

1

Я не согласен с вашей чрезмерно упрощенной причиной того, почему вы не должны называть виртуальную функцию. Во-первых, VTABLE на самом деле не определен стандартом C++ и, по сути, специфичен для реализации:

Когда VTable в C++ создан?

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

Конструкторы C++: почему этот вызов виртуальной функции небезопасен? http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html

Тем не менее, есть много, много причин не делать этого.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню