Что это за странный синтаксис двоеточия ( " :") в конструкторе?
недавно я видел такой пример:
#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и затем присваивая им значения, полученные в параметрах, эти члены будут инициализированы с этими значениями сразу же. Это может показаться не очень полезным дляfloats, но это может быть довольно экономия времени с пользовательскими классами, которые дорого построить.