2008-10-02 5 views
13

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

DiagramScene::DiagramScene(int slideNo, QRectF screenRect, MainWindow* parent) 
    : QGraphicsScene(screenRect, parent), 
    myParent(parent), 
    slideUndoImageCurrentIndex(-1), 
    nextGroupID(0), 
    m_undoInProgress(false), 
    m_deleteItemOnNextUndo(0) 
    line(0), 
    path(0) 
{ 
    /* Setup default brush for background */ 
    scDetail->bgBrush.setStyle(Qt::SolidPattern); 
    scDetail->bgBrush.setColor(Qt::white); 
    setBackgroundBrush(scDetail->bgBrush); 

} 
+1

Просто общая терминологическая заметка: речь идет о переменных-членах. Элементы-члены принадлежат объекту. Переменные класса не существуют в C++, в то время как они выполняются, например, Ruby, и служат более или менее целью статических переменных-членов C++. – xtofl 2008-10-02 11:20:28

ответ

26
  • Это более эффективно (в целом). Все члены класса инициализируются в конструкторе, независимо от того, явно ли вы их инициализируете или нет. Если вы не укажете инициализатор, будет запущен конструктор по умолчанию элемента. Если вы назначаете значение в теле конструктора, то оператор присваивания снова вызывается. Это не относится к скалярным значениям, как в вашем примере, поскольку скалярные значения не имеют конструкторов.
  • Вы не можете случайно присвоить значение дважды в списке инициализации.
  • Компилятор может проверить, чтобы порядок, в котором вы пишете инициализаторы, соответствует порядку, в котором члены определены в классе. Стандарт C++ требует, чтобы члены были инициализированы в том порядке, в котором они объявлены, независимо от порядка, который вы пишете инициализаторы. Проверка этого компилятора гарантирует, что программист знает, в каком порядке будут запускаться инициализаторы (опять же, это более важно для не-POD-элементов, чем для скаляров).
  • Ссылочные типы и const члены должны быть инициализированы в списке инициализаторов, потому что вы не можете назначить ссылку или члену const.
2

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

Кроме того, некоторые типы не могут быть построены по умолчанию (например, ссылки) и должны быть сконструированы в списке инициализации.

+0

Спасибо, добавлено примечание о ссылках. +1 – 2008-10-02 11:09:26

2

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

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

См C++ FAQ-Lite для более подробной информации

4

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

ПРИМЕЧАНИЕ: Есть моменты, когда для основных типов данных требуются списки инициализации - в частности, если тип является постоянным или ссылкой. Для этих типов данные могут быть инициализированы только один раз и поэтому не могут быть инициализированы в теле конструктора. См. this article для получения дополнительной информации.

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

Это моя рекомендация:

  • Вы научитесь, как списки инициализации.
  • Ваш сотрудник понимает правила для порядка инициализации членов (и избегает предупреждений).
3

В дополнение к Greg Hewgill's excellent answer - константные переменные должны быть установлены в списке инициализации.

+0

Спасибо, добавлено примечание о членах константы. +1 – 2008-10-02 11:09:59

0

Еще одно дополнение к ответу Грега: члены, имеющие типы без конструктора по умолчанию, должны быть инициализированы в списке инициализации.

0

Ответ Грега Хегвелла содержит отличный совет, но он не объясняет, почему компилятор генерирует предупреждение.

Когда список инициализатора конструктора обрабатывается компилятором, элементы инициализируются в том порядке, в котором они объявлены в объявлении класса, а не в том порядке, в котором они отображаются в списке инициализаторов.

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

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

Смежные вопросы