Что значит C() : a(12) {}

Недавно сейчас ООП в с++ и недавно наткнулся на вот такой интересный код в интернете:

struct A1
{
     A1()
     {cout << "A1";}
     ~A1
     { cout << "~A1";}
 };

struct A2
{
     A2()
     {cout << "A2";}
     ~A2()
     { cout << "~A2";}
 };
 class B
 {
 public:
        B()
        { cout << "B";}
        ~B()
        { cout << "~B";}
  private:
         A1 a;
  };
  class C : public B
  { 
  public:
        C() : a(12)
        { cout << "C"; }
         ~C()
        { cout << "~C"; }
  private: 
         A2 a;
    };

   int main()
   { C c; }

Можете пожалуйста мне объяснить, что такое

 C() : a(12) {}

Ответы (3 шт):

Автор решения: KoVadim

Конструкция вида

C() : a(12)
    { cout << "C"; }

это такой способ задать значение переменной класс a до вызова конструктора. Это способ считается достаточно хорошим и оптимальным в плане оптимизации. В принципе, он практически эквивалентный следующему коду

C()
    {a = 12; cout << "C"; }

внимание в текущем варианте кода а - это A2, у которого нет подходящего конструктора с одним int, Но есть подозрение, что автор неточно скопировал свой код и там было что то подходящее - например, там был тип int (или это был вопрос на тему "исправь, что бы компилировалось)

Но если Вы хотите сделать так как Вы написали изначально, то это можно (это же с++!)

// можно использовать макрос, можно constexpr функцию
//#define b

constexpr int b(int x) { return x;}

struct Test
{
    // а это битовое поле:)
    int a:b(2) {};
};

Родственный вопрос - Порядок вызова в списке инициализации конструктора

→ Ссылка
Автор решения: AlexGlebe

В определении конструктора класса после двоеточия обязательно нужно вызывать конструкторы базового класса, и элементов этого класса в правильном порядке.

Сначала базовые по-порядку, затем переменные по-порядку. Если базовые классы или элементы имеют конструкторы по-умолчанию, то их можно не указывать, они (конструкторы) будут вызваны без аргументов.

Ссылки например, не имеют коструктора по-умолчанию. И им нужен аргумент при создании объекта. Константные переменные тоже, конструируются только один раз и только в этом списке конструкции.

class BaseLeft {
public :
  // конструктора по-умолчанию нет
  // у типа int есть, но он не вызовется автоматически
  BaseLeft(int x) /* : i { } */ { i = x; }
private :
  int i ;
} ;

class BaseRight {
public :
  // конструктор по-умолчанию есть
  // у типа int есть, но его можно вызвать
  BaseRight() : i { -1 } { }
private :
  int i ;
} ;

class Son : public BaseLeft , public BaseRight {
public :
  
  // Son(int & j) : BaseLeft{} , BaseRight{} , bl{} , br{} , i{} ,l{} { c = 7 ; }
  
  // error: no matching function for call to 
  // ‘BaseLeft::BaseLeft(<brace-enclosed initializer list>)’
  // В классе BaseLeft нет конструктора по-умолчанию
  
  // error: assignment of read-only member ‘Son::c’
  // присваивание константе нельзя, только при инициализации
  
  // error: cannot bind non-const lvalue reference of type ‘int&’
  //  to an rvalue of type ‘int’
  // у ссылки нет конструктора по-умолчанию, ей нужен адрес куда ссылаться
  
  //Son(int & j) : BaseLeft{1} , BaseRight{} , bl{1} , br{} , i{}, l{j} , c{j} { }
  // хорошо
  
  Son(int & j) : BaseLeft{1} , bl{1} , l{j} , c{j} { i = 0 ; }
  // то-же самое
  
private :
  BaseLeft bl ;
  BaseRight br ;
  int i ;
  int & l ;
  int const c ;
};

Примечание :

Для встроенных типов (вроде int) стандарт решил, что если не вызывать прямо конструктор по-умолчанию, то можно вообще не инициализировать эту переменную. И в памяти это будет переменная со значением мусора в памяти.

→ Ссылка
Автор решения: ТарасПрограммер

Это прямая инициализация. Именно такой способ рекомендуется! Списки инициализации членов позволяют инициализировать члены, а не присваивать им значения. Это единственный способ инициализации констант и ссылок, которые являются переменными-членами вашего класса. Во многих случаях использование списка инициализации может быть более результативным, чем присваивание значений переменным-членам в теле конструктора. Списки инициализации работают как с переменными фундаментальных типов данных, так и с членами, которые сами являются классами.

→ Ссылка