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

161
12 марта 2019, 04:00

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

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

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

Answer 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; // Инициализация члена в определении класса
};

После чего выполнится присваивание в теле конструктора. Для сложных классов это может приводить к дополнительным расходам.

Т.о. инициализацию членов стоит производить либо в определении класса, либо в инициализаторе конструктора. Не стоит пытаться сделать нечто подобное непосредственно внутри тела конструктора.

Answer 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 более полон, чем мой.

Answer 3

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

this->msg = msg;
READ ALSO
Как сделать такую разметку с разным количеством слов в строке?

Как сделать такую разметку с разным количеством слов в строке?

Подскажите, пожалуйста, как сделать, чтобы слова из массива выводились в таком виде: то есть, чтобы на строчку влезало разное количество слов,...

165
Скачивание файла в Service/IntentService и отображение процесса скачивания

Скачивание файла в Service/IntentService и отображение процесса скачивания

У меня есть плеер, в котором можно скачивать песниДля скачивания на данный момент я использую IntentService, который выглядит вот так:

145
MySQL Could not create connection to database server

MySQL Could not create connection to database server

До перезагрузки компьютера всё работало отличноПосле перезагрузки netbeans пишет ошибку при компиляции проекта

282