2014-12-04 5 views
0

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

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

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

Child::Child() : 
Base() 
//<----- Why not here? 
//members initialization 
{ 
//<----- Why not here? 
//code 
} 
+1

Внутри тела конструктора 'Child' нет динамического типа' Child', а не 'Base'. Это 'Base' внутри конструктора' Base'. (Я не совсем уверен, меняется ли он до или после инициализации членов «Child», поэтому я не могу дать полный ответ). –

+0

Возможный дубликат [Можно ли вызвать виртуальную функцию для инициализации под-объекта базового класса?] (Http://stackoverflow.com/questions/25754796/may-i-call-a-virtual-function-to-initialize -a-base-class-sub-object) – Deduplicator

+0

@ravi стандарт явно позволяет вызывать виртуальные функции от конструктора, это просто считается ужасной практикой. – IdeaHat

ответ

1

Во многих источниках, книга и т.д. написано «не называют this-> виртуальным метода в детском конструкторе класса»

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

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

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

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

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

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

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

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

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

1

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

When is VTable in C++ created?

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

C++ constructors: why is this virtual function call not safe? http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html

Однако, есть много, много причин, чтобы не делать этого.

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