C++:调用的函数没有匹配:为什么需要一个空的构造函数?

问题描述 投票:0回答:1

当我尝试编译以下代码时。

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为参数的构造函数。

我明白,解决的办法是增加一个没有参数的构造函数,但为什么?

谢谢你的回答,最好的问候。

杰罗姆

c++ c++11 constructor default-constructor
1个回答
1
投票

(以下所有的ISO标准引用都是指 N4659:2017年3月科纳会议后工作草案C++17 DISC)


根据 [class.base.init]9జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ mya 成员 b属于 a,是默认初始化的,但 a 没有定义默认的构造函数。

In 如果给定的潜在构造的子对象没有被mem-initializer-id指定,则为非委托构造函数。 (包括 没有mem-initializer-list。 因为构造函数没有ctor-initializer)。) 然后

  • (9.1) 如果该实体 是一个非静态数据成员,它 有一个默认的成员初始化器 [.]该实体 从其默认成员初始化器 如[dcl.init]中指定的那样。
  • (9.2) 否则,如果实体是匿名联合体或变异成员([class.union.anon]),不执行初始化。
  • (9.3)否则,如果实体是匿名联盟或变体成员([class.union.anon]),则不进行初始化;(9.3)否则。实体是默认初始化的。

这里,正如 mya 没有和默认的成员初始化器一起声明。[class.base.init]9. 适用。

的例子。[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 适用。

mem-initializer中的表达式列表或括号中的-init-列表用于根据[dcl.init]的初始化规则初始化指定的子对象(如果是委托构造函数,则初始化完整的类对象),用于直接初始化。 [ 例子.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;
}

8
投票

在构造函数中 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
}
© www.soinside.com 2019 - 2024. All rights reserved.