为什么派生类的构造函数在其初始化列表中使用base的默认构造函数?

时间:2016-04-22 15:59:25

标签: c++ derived-class default-constructor

以下是我的问题示例:

class MyBaseClass
{
 public:
    MyBaseClass(): my_bool(false), my_value(0)
    {}
    MyBaseClass(bool b, int i): my_bool(b), my_value(i)
    {}

 private:
    bool my_bool;
    int my_value;
}

class MyDerivedClass1 : public ::MyBaseClass
{
 public:
    MyDerivedClass1(double d): my_double(d)
    {}
 private:
    double my_double;
}

class MyDerivedClass2 : public ::MyBaseClass
{
 public:
    MyDerivedClass2(double d): MyBaseClass(), my_double(d)
    {}
 private:
    double my_double;
}

为什么MyDerivedClass1不是一种初始化派生类的方法,而不是像MyDerivedClass2那样显式初始化基类?

我想我不明白为什么我不能只依靠C ++调用我的基础构造函数?我知道如果我希望它们初始化为不同的东西,我必须在初始化列表中调用其他构造函数,但我想要的只是要调用的基础构造函数。

2 个答案:

答案 0 :(得分:4)

在初始化程序列表中提供默认构造的基类或不提供它之间没有区别。完全是你的风格,你用什么。 (或公司)

一般情况下,假设您始终初始化您的成员,我会说您有2个选项(让构建者超出范围)。

选项1:初始化init-list中的所有成员。

如果您与C ++ 98兼容,则应使用此选项。它的优势在于您可以在一个列表中定义所有构造参数,从而可以轻松搜索。 (除非你有50多名成员)

当你有多个构造函数时,这个选项的缺点是很多重复。

有了这个,你可以有三种变体:

  • 跳过默认初始化的课程,这会缩短列表,但很难检查您是否打算忘记'它。 (想想用ptr替换一个类)
  • 默认初始化所有成员,这会使列表更长,但显示意图
  • 通过使用tempuary进行复制构造,明确提供您正在初始化的类

选项2:在声明中初始化所有成员,构造函数参数除外

此选项假定您初始化类声明中的所有内容。您可以再次显式调用默认构造函数,最好使用braced init,因为圆括号被解释为函数声明。

在初始化列表中,您只需要放置链接到构造参数的成员。

此选项的优点是可读性(特别是对于大型类)。缺点是这会将您的编译器选项限制为“现代”和“现代”。编译器。

基础课程

如果我们再次考虑基类并将它们视为成员,那么一致的方法是明确地为选项1声明它们,而不是为选项2编写它们。

我个人喜欢选项2,因为我经常会遇到有太多成员的类,并且检查是否所有成员都已经初始化了,这很容易用这个。

然而,由于遗留原因,通常会使用选项1,以保持代码的一致性。

<强> POD

重要的是POD(普通旧数据类型),如int,double ... 如果你没有初始化它们,你会得到一些随机数据。这使得显式初始化它们很重要,无论您使用哪种方法。

<强>结论

所以最后,这完全是一种没有功能差异的风格问题。

答案 1 :(得分:2)

虽然在大多数情况下没有语义差异且问题主要是样式之一,但有一种情况是区别的:基类的默认构造函数不是用户提供的。

不同之处在于,不在成员初始值设定项列表中的基础是默认初始化,而明确写入Base() value-initializes 它,如果默认构造函数不是用户提供的,则执行零初始化。

因此:

struct A { int i; };
struct B : A {
    B() : j(i) {}  // may be undefined behavior
    int j;
};

struct C : A {
    C() : A(), j(i) {} // OK; both i and j are zero
    int j;
};