如果您提供构造函数而不为所述子对象指定初始化程序,则每个子对象都将被默认初始化。
该标准第 8.5 节规定:
如果没有为对象指定初始化器,则该对象是默认初始化的;如果不执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。[ 注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2。——尾注]
然后
默认初始化类型的对象T
意味着:
- if
T
是(可能是cv-qualified)类类型,T
调用默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);
- 如果 T 是数组类型,则每个元素都是默认初始化的;
- 否则,不执行初始化。
如果程序要求对 const 限定类型的对象进行默认初始化T
,T
则应是具有用户提供的默认构造函数的类类型。
初始化子对象有两种方法:在ctor-initializer-list 中,以及在成员声明中的大括号或相等初始化器中(对于非静态成员,后者在 C++11 中是新的)。
实际上,这意味着当您不提供初始值设定项时,原始类型的变量(例如int
and char
)会保留之前留在内存中的任何值。在大多数情况下,很难预测这将是什么值,但您应该知道它可能是剩余的敏感数据,例如密码。
在初始化静态存储持续时间的变量(例如命名空间范围内的对象及其成员)的情况下,标准进一步提供(同一部分):
在任何其他初始化发生之前,在程序启动时,每个静态存储持续时间的对象都被初始化为零。
如果您没有定义构造函数,这与值初始化期间发生的情况略有不同:
对类型对象进行值初始化T
意味着:
- 如果
T
是具有用户提供的构造函数的(可能是cv 限定的)类类型,则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化格式错误);
- if
T
是没有用户提供的构造函数的(可能是cv 限定的)非联合类类型,则该对象被零初始化,并且如果T
的隐式声明的默认构造函数是非平凡的,则调用该构造函数。
- 如果
T
是数组类型,则每个元素都是值初始化的;
- 否则,对象被零初始化。
但效果是一样的——原始成员设置为零,所有其他成员都调用了它们的零参数构造函数。
nneonneo 建议显式初始化所有成员是好的,因为仅对静态存储持续时间的变量进行零初始化通常会导致难以发现的错误。但是使用大括号或相等初始化器技术是完全可行的:
class Transaction
{
int no = 0;
char dollar = 0;
public:
Transaction();
~Transaction();
}