构造函数、类内初始化和初始化列表是C++中类成员变量初始化的三种方式,它们在类的定义和对象创建过程中发挥着重要作用。
对于类内初始化是C++11才开始支持的语法,因此本文重点讲解类内初始化与其余二者的辨析。
构造函数
自动调用,用来初始化成员变量的函数。默认构造函数十分重要。由三部分组成:无参构造、全缺省构造和系统自动生成的默认构造函数。
当我们显示的定义出构造函数之后,系统便不会生成默认构造函数。
这便是无参的默认构造。(当我们不去操作,内置类型不会进行处理)
class A
{
public:
A()
{}
int _a ;
int _b ;
};
这是全缺省的构造。
A(int a = 22, int b = 11)
{
_a = a;
_b = b;
}
当我们什么都不写,就会生成系统默认构造
总结
- 构造函数在对象创建时自动调用;
- 可以重载,即一个类可以有多个构造函数;
- 构造函数可以带有参数,用于初始化成员变量。
初始化列表
初始化列表是一种在构造函数中初始化成员变量的方式,它使用花括号{}将成员变量与初始值一一对应。初始化列表的执行顺序与成员变量在类中的声明顺序相同。
A(int a = 22, int b = 11)
:_a(a)
,_b(b)
{}
这便是初始化列表的初始化方式
总结
- 初始化列表在构造函数的函数体执行前调用;
- 对于常量成员和引用成员,必须使用初始化列表进行初始化;
- 初始化列表可以提高效率,因为它直接初始化成员变量,而不是先默认构造再赋值
类内初始化
这是C++11才支持的语法。允许在类定义时直接为成员变量赋初值。这种方式简化了构造函数的编写,使代码更加简洁。
C++11 标准允许所有类型的非静态数据成员在类定义中进行类内初始化(in-class initializer),包括内置类型、复合类型(例如指针、引用)、用户定义的类型(例如类类型)等。
class MyClass {
public:
// 内置类型
int intValue = 10;
// 复合类型
int* intPointer = nullptr;
const int& intRef = intValue; // 引用必须被初始化为有效的对象或函数
// 用户定义类型
std::string strValue = "Hello";
// 构造函数
MyClass() {
// 构造函数体可以为空,因为所有成员都已类内初始化
}
};
类内初始化的规则是:
- 初始化表达式必须能够用于常量表达式,这意味着它必须能够在编译时被求值。
- 对于非静态成员来说,类内初始化不适用于数组类型,除非它们是静态的。
- 对于用户定义的类型,类内初始化通常调用该类型的默认构造函数。
当我们借助A建立对象时 A a;这种建立方式必须要有默认构造函数(全缺省、无参、默认)
class A
{
public:
A(int a = 22, int b = 11)
:_b(b)
{}
int _a = 20;
int _b = 10;
};
int main()
{
A a;
return 0;
}
当我们写出了构造函数时,a、b先进行类内初始化,变成20 10;进入初始化列表之后,b被修正为11.。
cout << a._a << " " << a._b << endl; 所以打印结果是,
20 11
总结来说,成员变量的缺省值是在没有构造函数或者构造函数没有提供初始化值时使用的,而初始化列表是在构造函数中明确指定成员变量初始值的方式。如果两者同时存在,初始化列表的值会优先使用。
全缺省的构造、初始化列表、类内初始化是允许同时存在的!
当采用A a;这种方式去定义对象时,必须保证存在默认构造函数。