以下是我的问题示例:
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 :(得分:4)
在初始化程序列表中提供默认构造的基类或不提供它之间没有区别。完全是你的风格,你用什么。 (或公司)
一般情况下,假设您始终初始化您的成员,我会说您有2个选项(让构建者超出范围)。
选项1:初始化init-list中的所有成员。
如果您与C ++ 98兼容,则应使用此选项。它的优势在于您可以在一个列表中定义所有构造参数,从而可以轻松搜索。 (除非你有50多名成员)
当你有多个构造函数时,这个选项的缺点是很多重复。
有了这个,你可以有三种变体:
选项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;
};