Что это за странный синтаксис двоеточия ( " :") в конструкторе?
недавно я видел такой пример:
#include <iostream>
class Foo {
public:
int bar;
Foo(int num): bar(num) {};
};
int main(void) {
std::cout << Foo(42).bar << std::endl;
return 0;
}
что это странно : bar(num)
в смысле? Это как-то инициализирует переменную-член, но я никогда не видел этот синтаксис раньше. Это похоже на вызов функции / конструктора, но для int
? Для меня это не имеет смысла. Может быть, кто-нибудь просветит меня. И, кстати, есть ли другие эзотерические языковые функции, подобные этой, которые вы никогда не найдете в обычной книге на C++?
12 ответов:
Это список инициализации членов. Вы должны найти информацию об этом в любом хорошая книга на C++.
в большинстве случаев следует инициализировать все объекты-члены в списке инициализации членов (однако обратите внимание на исключения, перечисленные в конце записи FAQ).
точка выноса из записи FAQ заключается в том, что
при всех прочих равных условиях, ваш код будет работать быстрее, если вы используете списки инициализации, а не присваивания.
Foo(int num): bar(num)
эта конструкция называется Список Инициализаторов Членов в C++.
проще говоря, это инициализирует ваш значение
num
.
в чем разница между инициализацией и присваиванием внутри конструктора?
Член Инициализации:
Foo(int num): bar(num) {};
- Члены Назначение:
Foo(int num) { bar = num; }
существует значительное разница между инициализацией элемента с помощью списка инициализаторов элементов и присвоением ему значения внутри тела конструктора.
когда вы инициализации поля через список инициализаторов членов конструкторы будут вызваны один раз, и объект будет построен и инициализирован в одной операции.
если вы используете задание затем поля будут сначала инициализированы с помощью конструкторов по умолчанию, а затем повторно (через оператор присваивания) с фактическими значениями.
как вы видите, в последнем есть дополнительные накладные расходы на создание и назначение, которые могут быть значительными для пользовательских классов.
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
не имеет конструктора по умолчанию, поэтому для инициализации его члена нужно будет использовать список инициализаторов членов.
важные моменты при использовании члена Списки Инициализаторов:
переменные-члены класса всегда инициализируются в том порядке, в котором они объявлены в классе.
они не инициализируются в том порядке, в котором они указаны в списке инициализатора.
Короче говоря, список инициализации членов не определяет порядок инициализации.Учитывая вышеизложенное, всегда рекомендуется поддерживать один и тот же порядок членов для Инициализация членов как порядок, в котором они объявлены в определении класса. Это связано с тем, что компиляторы не предупреждают, если два порядка различны, но относительно новый пользователь может перепутать список инициализаторов членов как порядок инициализации и написать некоторый код, зависящий от этого.
это инициализация конструктора. Это правильный способ инициализации членов в конструкторе класса, так как он предотвращает вызов конструктора по умолчанию.
рассмотрим эти два примера:
// Example 1 Foo(Bar b) { bar = b; } // Example 2 Foo(Bar b) : bar(b) { }
Пример 1:
Bar bar(); // default constructor bar = b; // assignment
Пример 2:
Bar bar(b) // copy constructor
все дело в эффективности.
Это называется списком инициализации. Это альтернативный способ инициализации членов класса. Есть преимущества использования этого вместо простого присвоения новых значений членам в теле конструктора, но если у вас есть члены класса, которые являются константы или ссылки они должны быть инициализирован.
это не неясно, это синтаксис списка инициализации C++
в основном, в вашем случае,
x
устанавливается с_x
,y
С_y
,z
С_z
.
другой уже объяснил вам, что синтаксис, который вы наблюдаете, называется "Список инициализаторов конструктора". Этот синтаксис позволяет выполнять пользовательскую инициализацию базовых подобъектов и членских подобъектов класса (в отличие от разрешения им инициализировать по умолчанию или оставаться неинициализированными).
Я просто хочу отметить, что синтаксис, который, как вы сказали, "выглядит как вызов конструктора", не обязательно является вызовом конструктора. В языке C++
()
синтаксис-это всего лишь одна стандартная форма из синтаксис инициализации. Он интерпретируется по-разному для разных типов. Для типов классов с пользовательским конструктором это означает одно (это действительно вызов конструктора), для типов классов без пользовательского конструктора это означает другое (так называемый инициализация значением ) для пустых()
) и для неклассовых типов это снова означает что-то другое (поскольку неклассовые типы не имеют проектировщики.)в вашем случае элемент данных имеет тип
int
.int
не является типом класса, поэтому он не имеет конструктора. Для типаint
этот синтаксис означает просто "инициализироватьbar
со значениемnum
" и все тут. Это делается просто так, напрямую, без участия конструкторов, так как, еще раз,int
не является типом класса, поэтому он не может иметь никаких конструкторов.
Я не знаю, как вы могли пропустить это, он довольно простой. Это синтаксис для инициализации переменных-членов или конструкторов базового класса. Он работает для простых старых типов данных, а также объектов класса.
Это список инициализации. Он инициализирует члены перед запуском тела конструктора. Рассмотрим
class Foo { public: string str; Foo(string &p) { str = p; }; };
vs
class Foo { public: string str; Foo(string &p): str(p) {}; };
в первом примере str будет инициализирован его конструктором без аргументов
string();
перед телом конструктора Foo. Внутри конструктора foo,
string& operator=( const string& s );
будет вызван на 'str', как вы делаете str = p;
как во втором примере, ул. будут инициализированы сразу мимо вызов его конструктора
string( const string& s );
С 'p' в качестве аргумента.
вы правы, это действительно способ инициализации переменных-членов. Я не уверен, что в этом есть много пользы, кроме четкого выражения того, что это инициализация. Наличие "bar=num" внутри кода может быть перемещено, удалено или неверно истолковано гораздо легче.
есть еще одно "благо"
Если тип переменной-члена не поддерживает инициализацию null или если его ссылка (которая не может быть инициализирована null), то у вас нет выбора, кроме как предоставить список инициализации
Это список инициализации конструктора. Вместо построения по умолчанию
x
,y
иz
и затем присваивая им значения, полученные в параметрах, эти члены будут инициализированы с этими значениями сразу же. Это может показаться не очень полезным дляfloat
s, но это может быть довольно экономия времени с пользовательскими классами, которые дорого построить.