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

问题描述:

这里是我的问题的一个例子:为什么派生类的构造函数应该在其初始化列表中使用基类的默认构造函数?

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++调用我的基构造函数?我知道如果我想让它们初始化为不同的东西,我必须在初始化列表中调用另一个构造函数,但是我想要的只是要调用的基础构造函数。

+0

你得到一个错误?如果您调用基构造函数,编译器应自动调用基类的默认构造函数。 – NathanOliver

+0

@NathanOliver - 不,我没有得到一个错误。我在代码审查中被告知将基础构造函数包含在MyDerivedClass2中,我问为什么。没有人能给我一个很好的理由,缺少“文档”。所以我在问为什么在这里。另外,正如我在最佳实践中谷歌周刊所说的那样,调用基础构造函数和我的同事选定这些原因,但我不知道为什么我应该在这种情况下。我希望有人有一个很好的理由。 – TWhite

+3

这听起来像是一个编码标准问题,在这种情况下,答案可能是沿着“它表明你已经考虑它并决定构建基础的默认值是合适的,而不是忘记它”。 –

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

一般来说,假设你总是初始化你的成员,我会说你有2个选项(让我们让构造函数超出范围)。

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

如果您与C++ 98兼容,则应使用此选项。它的优点是您可以将所有的施工参数定义在一个列表中,方便查找。 (除非你有50多个成员)

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

有了这个,你可以有3个变种为他们:

  • 跳过默认的初始化类,这使得短名单,虽然这是很难检查您是否打算“忘记”了。 (想想一个PTR给它更换类)
  • 默认初始化所有成员,这使得名单更长,但清楚地表明意图
  • 明确规定要初始化类,通过复制与tempuary contructing

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

此选项假定您初始化类声明的一切。再次,你可以明确地调用默认的构造函数或不使用,最好使用加载的init,因为圆括号被解释为函数声明。

在初始化程序列表中,您只需将与链接到构造参数的成员放在一起。

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

基类

如果我们再考虑基类,看看他们,如果他们的成员,一致的办法是明确地宣布他们选择1和不写他们的选项2。

Personnally我喜欢选项2,因为我经常遇到太多会员的班级,并且检查是否所有会员都已经初始化,这一点很容易。

然而选项1经常被使用,因为传统为了保持代码的一致性。

POD

重要提的还有荚(普通老式的数据类型),如int,双... 如果你不初始化他们,你得到一些随机数据。无论您使用何种方法,这都明确地初始化它们非常重要。

结论

所以在最后,这一切都与一个没有功能差异的风格问题。

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

的差异来自于事实基础,是不是在成员初始化列表是默认初始化,而明确地写Base()值初始化它,执行零初始化,如果默认的构造函数ISN”用户提供。

这样:

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; 
}; 
+0

我会一直是零吗?这个编译器是否独立? – TWhite

+0

我是否会被初始化?不是默认的构造函数跳过它吗? – JVApen