当成员具有另一个类作为其类型时,构造函数中的成员初始化

时间:2015-07-16 05:28:09

标签: c++

我最近开始学习C ++并且一直在使用cplusplus.com的教程来学习。我进入了类部分,看到了如何初始化成员而不在构造函数的主体中键入它。起初这看起来很简单,但他们的例子让我很困惑。这是:

// member initialization
#include <iostream>
using namespace std;

class Circle {
    double radius;
  public:
    Circle(double r) : radius(r) { }
    double area() {return radius*radius*3.14159265;}
};

class Cylinder {
    Circle base;
    double height;
  public:
    Cylinder(double r, double h) : base (r), height(h) {}
    double volume() {return base.area() * height;}
};

int main () {
  Cylinder foo (10,20);

  cout << "foo's volume: " << foo.volume() << '\n';
  return 0;
}

困扰我的部分是Cylinder类,具体来说是:

Cylinder(double r, double h) : base (r), height(h) {}

在该类的早期,声明了一个名为Circle的“base”的成员对象。然后,在圆柱构造函数中,这个“基础”对象被设置为“r”,这是一个双重的:

base (r), height(h) {}

我的问题是,当它是“Circle”类型时,如何将成员“base”初始化为double?另外,我尝试做的事情(我认为)本质上是相同的,但我在构造函数的主体中初始化了“base”:

Cylinder(double r, double h)
{
    base = r;
    height = h;
}

这给我留下了编译错误:“错误:没有匹配函数来调用'Circle :: Circle()'”

如果有人能为我解决这个困惑,我会非常感激。感谢。

3 个答案:

答案 0 :(得分:2)

  

会员&#34; base&#34;当它是&#34; Circle&#34;?

时,被初始化为double

成员初始化列表将调用base的相应构造函数,Circle有一个构造函数,其中double作为参数,因此它可以正常工作。

base = r;也会编译,因为r可以通过上面的构造函数隐式转换为Circle,然后将调用operator=(const Circle&)(由编译器隐式生成)。但是没有成员初始化列表base需要首先由默认构造函数初始化,Circle没有。那是什么错误信息。

答案 1 :(得分:0)

在成员初始化列表中查看此link。特别是以下内容适用于您的情况:

  

1)使用直接初始化初始化由class-or-identifier命名的基类或成员,如果expression-list为空,则初始化值初始化

  

在构成构造函数体的复合语句开始执行之前,完成所有直接碱基,虚拟碱基和非静态数据成员的初始化。成员初始化列表是可以指定这些对象的非默认初始化的地方。

特别是在您的示例中,类型base的{​​{1}}在成员初始值设定项列表中使用Circle进行了直接初始化。但如果成员初始值设定项列表中未显示double,则默认初始化。但是,编译器不会为类base合成默认构造函数,因为还有其他用户定义的构造函数。这就是为什么你看到错误:“错误:没有匹配函数来调用'Circle :: Circle()”

您可以使用Circle

创建默认构造函数
= default

答案 2 :(得分:0)

Cylinder(double r, double h) : base (r), height(h) {}  

上面的代码使用初始化列表构造对象,&#34; base(r),height(h)&#34;,这是base的初始化真正发生的地方:base的构造函数被调用。

如果你将base放入构造函数体中,就像这样:

Cylinder(double r, double h)
{
    base = r;
    height = h;
}
由于初始化列表中没有任何内容,但是在此阶段必须进行base的初始化,编译器会调用base的no-parameter构造函数来执行此操作。但是你没有提供这样的构造函数,而是一个带有一个参数的构造函数,在这种情况下,编译器也不会生成没有参数的构造函数,因此编译器无法找到没有参数的base的构造函数,并且会引发错误。< / p>

要解决此问题,您只需要提供一个没有Circle类参数的构造函数:

class Circle {
    double radius;
  public:
    Circle(double r) : radius(r) { }
    Circle():radius(1.0){} // just example
    double area() {return radius*radius*3.14159265;}
};

然后你的代码就行了。但是你可能需要注意&#34; base = r&#34;在Cylinder的构造函数体中:

  1. 它将调用&#34; Circle(double r):radius(r){}&#34;构建一个 使用&#34; r&#34;使用圆形类型的临时对象作为参数
  2. 然后它将执行逐位复制以复制temp中的所有内容 反对&#34; base&#34;因为你没有提供作业方法。
  3. 关于会员&#34;身高&#34;在Cylingder中,因为它是原始类型,通常可以在初始化列表中初始化它,或者将它保留在内存中,然后在Cylinder的构造函数体中为它指定一个值。但如果你想让&#34;身高&#34;在转到构造函数体之前已经确定了值,你必须在初始化中初始化它