Foo(int num): bar(num)
Эта конструкция называется Список инициализирующих элементов в C ++.
Проще говоря, инициализирует вашего члена bar
значением num
.
В чем разница между инициализацией и назначением внутри конструктора?
Инициализация элемента:
Foo(int num): bar(num) {};
Назначение участника:
Foo(int num)
{
bar = num;
}
Существует значительная разница между инициализацией элемента с использованием списка инициализатора элемента и присвоением ему значения внутри тела конструктора.
Когда вы инициализируете поля через список инициализаторов Member, конструкторы будут вызываться один раз, а объект будет создан и инициализирован за одну операцию.
Если вы используете присваивание , тогда поля будут сначала инициализированы конструкторами по умолчанию, а затем переназначены (через оператор присваивания) с фактическими значениями.
Как вы видите, в последнем имеются дополнительные издержки создания и назначения, которые могут быть значительными для пользовательских классов.
Cost of Member Initialization = Object Construction
Cost of Member Assignment = Object Construction + Assignment
Последнее фактически эквивалентно:
Foo(int num) : bar() {bar = num;}
В то время как первое эквивалентно просто:
Foo(int num): bar(num){}
Для встроенных (ваш пример кода) или членов класса POD практических затрат нет.
Когда вы ДОЛЖНЫ использовать список инициализаторов участников?
Вы будете (скорее вынуждены) использовать список инициализатора участника, если:
- В вашем классе есть референтный член
- В вашем классе есть нестатический член const или
- У вашего ученика нет конструктора по умолчанию или
- Для инициализации членов базового класса или
- Когда имя параметра конструктора совпадает с элементом данных (на самом деле это НЕ ДОЛЖНО)
Пример кода:
class MyClass
{
public:
//Reference member, has to be Initialized in Member Initializer List
int &i;
int b;
//Non static const member, must be Initialized in Member Initializer List
const int k;
//Constructor’s parameter name b is same as class data member
//Other way is to use this->b to refer to data member
MyClass(int a, int b, int c):i(a),b(b),k(c)
{
//Without Member Initializer
//this->b = b;
}
};
class MyClass2:public MyClass
{
public:
int p;
int q;
MyClass2(int x,int y,int z,int l,int m):MyClass(x,y,z),p(l),q(m)
{
}
};
int main()
{
int x = 10;
int y = 20;
int z = 30;
MyClass obj(x,y,z);
int l = 40;
int m = 50;
MyClass2 obj2(x,y,z,l,m);
return 0;
}
MyClass2
не имеет конструктора по умолчанию, поэтому его нужно инициализировать с помощью списка инициализаторов элементов.
- Базовый класс
MyClass
не имеет конструктора по умолчанию, поэтому для инициализации его члена потребуется использовать список инициализаторов членов.
Важные моменты, на которые следует обратить внимание при использовании списков инициализаторов:
Переменные-члены класса всегда инициализируются в том порядке, в котором они объявлены в классе.
Они не инициализируются в том порядке, в котором они указаны в списке инициализатора участника.
Короче говоря, список инициализации члена не определяет порядок инициализации.
Учитывая вышеизложенное, всегда рекомендуется поддерживать тот же порядок членов для инициализации членов, что и порядок, в котором они объявлены в определении класса. Это связано с тем, что компиляторы не предупреждают, если два порядка различаются, но относительно новый пользователь может запутать список инициализаторов членов как порядок инициализации и написать некоторый код, зависящий от этого.