当我尝试编译以下代码时。
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为参数的构造函数。
我明白,解决的办法是增加一个没有参数的构造函数,但为什么?
谢谢你的回答,最好的问候。
杰罗姆
(以下所有的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;
}
在构造函数中 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
}