C ++: нет соответствующей функции для вызова: зачем нужен пустой конструктор? - PullRequest
3 голосов
/ 16 июня 2020

Когда я пытаюсь скомпилировать следующий код:

class a {

  int i;

  public :
  a(int);
};

class b {
  a mya;  
  int j;

  public:
  b(int);

};

a::a(int i2) {
  i=i2;
}

b::b(int i2) {
  mya=a(i2); 
  j=2*i2;
}

int main() {

}

, я получаю следующие ошибки:

prog.cpp:21:12: error: no matching function for call to ‘a::a()

 b::b(int i2) {
            ^
prog.cpp:17:1: note: candidate: ‘a::a(int)

 a::a(int i2) {
 ^
prog.cpp:17:1: note:   candidate expects 1 argument, 0 provided
prog.cpp:1:7: note: candidate: ‘constexpr a::a(const a&)’
 class a {
       ^
prog.cpp:1:7: note:   candidate expects 1 argument, 0 provided
prog.cpp:1:7: note: candidate: ‘constexpr a::a(a&&)

prog.cpp:1:7: note:   candidate expects 1 argument, 0 provided

Кажется, ожидается конструктор без аргументов для класса a . Я не понимаю, почему, единственный раз, когда я создаю объект типа a, я вызываю конструктор, который принимает в качестве аргумента int.

Я понимаю, что решением было бы добавить конструктор без аргументов для a. Но почему?

Спасибо за ответы, с наилучшими пожеланиями,

Джером

Ответы [ 2 ]

8 голосов
/ 16 июня 2020

В конструкторе b, mya=a(i2); - это присваивание (но не инициализация). Перед вводом тела конструктора mya пытается быть инициализированным по умолчанию, но a не имеет конструктора по умолчанию.

Как вы сказали, вы можете добавить конструктор по умолчанию для a, затем mya будет инициализирован по умолчанию, а затем будет назначен внутри конструктора b.

Лучший способ - инициализировать mya в списке инициализаторов членов .

b::b(int i2) : mya(i2) {
//           ^^^^^^^^^
  j=2*i2; // this could be moved to member initializer list too
}
1 голос
/ 16 июня 2020

(Все приведенные ниже ссылки на стандарты ISO относятся к N4659: рабочий проект после выпуска Kona за март 2017 г. / DIS C ++ 17 )


Согласно [class.base.init] / 9 , член mya из b, который имеет тип a, инициализируется по умолчанию, но a определяет нет конструктора по умолчанию:

В конструктор без делегирования, если данный потенциально сконструированный подобъект не обозначен идентификатором mem-initializer-id (включая случай, когда нет mem-initializer-list , потому что конструктор не имеет ctor-initializer), тогда

  • (9.1) , если объект нестатический c элемент данных, который имеет инициализатор члена по умолчанию [...] объект инициализируется из его инициализатора члена по умолчанию , как указано в [dcl.init];
  • (9.2) в противном случае, если сущность является анонимным объединением или вариантным членом ([class.union.anon]), инициализация не выполняется;
  • (9.3) в противном случае, сущность инициализируется по умолчанию.

Здесь, поскольку mya не объявляется вместе с инициализатором члена по умолчанию, * 1045 Применяется * [class.base.init] /9.3.

Пример [class.base.init] / 9 охватывает даже этот конкретный случай:

[...] [Пример:

struct A {
  A();
};

struct B {
  B(int);
};

struct C {
  C() { }               // initializes members as follows:
  A a;                  // OK: calls A​::​A()
  const B b;            // error: B has no default constructor
  int i;                // OK: i has indeterminate value
  int j = 5;            // OK: j has the value 5
};

- конечный пример]

Вы можете решить эту проблему, предоставив инициализатор члена по умолчанию для mya, таким образом, что [class.base.init] /9.1 применяет

class b {
  a mya{42};  // default member initializer
  int j;

  public:
  b(int);
};

или используйте список инициализаторов членов в определении конструктора b; b::b(int), так что применяется [class.base.init] / 7 :

Список-выражений или список-инициализации в фигурных скобках в инициализаторе памяти используется для инициализировать назначенный подобъект (или, в случае делегирующего конструктора, полный объект класса) в соответствии с правилами инициализации [dcl.init] для прямой инициализации. [Пример:

struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
  D(int);
  B1 b;
  const int c;
};

D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
D d(10);

- конечный пример] [...]

, таким образом, прямая инициализация элемента mya:

b::b(int i2) : mya(i2) {
           //  ^^^^^^^- member initializer list
  j=2*i2;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...