Страницы

Поиск по вопросам

понедельник, 2 декабря 2019 г.

Двоеточие в определении конструктора

#cpp #конструктор


У меня возникла проблема с пониманием синтаксиса. Увидел вот такой конструктор: 

foo(char *msg) : msg(msg) { ..... }


Что значит двоеточие после аргумента в первых скобках?
    


Ответы

Ответ 1



Область кода за двоеточием и до начала тела конструктора называется инициализатором конструктора. Используется как для инициализации членов класса, так и для вызова конструктора базового/базовых классов, т.е. по сути, инициализации базовой составляющей. Также здесь может быть вызов другого конструктора текущего класса (делегирование конструкторов, начиная с c++11). Без инициализатора конструктора не обойтись, если в классе присутствует член ссылочного типа или константа, или член класса, у которого нет конструктора по умолчанию: struct S { S(int) {} // Конструктор с параметром. Не является конструктором по умолчанию. }; class B { public: B(int i) : i(i), r(i), s(i) { // this->i = i; // Ошибка. Нельзя присваивать константе. // r = i; // Ошибка. Не является инициализацией ссылки. // s = S(i); // Ошибка. `s` должен быть создан в инициализаторе конструктора. } private: const int i; int& r; S s; }; т.к. код, начинающийся за фигурной скобкой будет приводить уже не к инициализации члена, а к присваиванию ему значения, чего нельзя сделать для упомянутых ранее ссылок или констант. Дополнительно стоит заметить (как было упомянуто в комментарии Monah Tuk), что если член-класса не инициализирован явно в инициализаторе конструктора и при этом ему присваивается значение в теле конструктора, то он сначала будет инициализирован конструктором по умолчанию (или инициализацией в определении класса (c++11)): class D { int i = 42; // Инициализация члена в определении класса }; После чего выполнится присваивание в теле конструктора. Для сложных классов это может приводить к дополнительным расходам. Т.о. инициализацию членов стоит производить либо в определении класса, либо в инициализаторе конструктора. Не стоит пытаться сделать нечто подобное непосредственно внутри тела конструктора.

Ответ 2



class foo { public: foo(int a) : a(a) {} // эквивалентно foo(int a) { this->a = a; } private: int a; } Это вообще-то база синтаксиса определения конструкторов в плюсах. Еще может быть: class foo : public bar { public: foo(int a) : bar(a) { ... } } В этом случае, после двоеточия вызывается конструктор базового класса. ЕМНИП (могу ошибаться), в случае базового класса это единственный верный способ его вызова, т.е. написать вот так: foo(int a) { bar(a); ... } будет неверно. П.С. Думаю, ответ alexolut более полон, чем мой.

Ответ 3



Это использование списка инициализации (Initialization List) для конструктора. Эта запись эквивалентна строчке кода в начале конструктора this->msg = msg;

Комментариев нет:

Отправить комментарий