1.什么是默认初始化
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值;而赋值的含义是把变量的当前值擦除,以一个新值来替代。
默认初始化,顾名思义,在定义变量时如果没有为其指定初始化值,则该变量会被 C++ 编译器赋予默认的值。而变量被赋予的默认值到底是什么,则取决于变量的数据类型和变量的定义位置。
2.初始化的语法
与 C 语言不同,在 C++ 中局部变量可以随时用到随时定义。
#include<iostream>
using namespace std;
int main()
{
int a = 5;
int b = { 5 };
int c{ 5 };
int x = 3.5f; // 隐式类型转换
int y = { 3.5f }; // 编译不通过
int z{ 3.5f }; // 编译不通过
int i(3);
int j = int(3);
int* p = new int(3);
int arr1[4] = { 10, 12, 24, 34 };
int* arr2 = new int[4]{ 10, 12, 24, 34 };
return 0;
}
3.内置类型
3.1 全局变量
定义在任何函数之外的未初始化的内置类型变量(即全局变量)会被默认初始化为 0
。
-
数值数据类型的未初始化全局变量的默认初始值为
0
-
bool 类型的未初始化的全局变量的默认初始化值为
false
(也就是0
) -
char 类型的未初始化的全局变量的默认初始化值为
'\0'
(空字符,字符串结束标志,ASCII码值为0
)
#include <iostream>
using namespace std;
short a;
int b;
long c;
long long d;
float e;
double f;
bool g;
char h;
int main()
{
cout << "short类型的默认初始值为:" << a << endl;
cout << "int类型的默认初始值为:" << b << endl;
cout << "long类型的默认初始值为:" << c << endl;
cout << "long long类型的默认初始值为:" << d << endl;
cout << "float类型的默认初始值为:" << e << endl;
cout << "double类型的默认初始值为:" << f << endl;
cout << "bool类型的默认初始值为:" << g << endl;
if (h == '\0')
{
cout << "char类型的默认初始值为\'\\0\'" << endl;
}
else
{
cout << "char类型的默认初始值不是\'\\0\'" << endl;
}
return 0;
}
3.2 局部变量
定义在函数体(包括main函数)内部的未初始化的内置类型变量(即局部变量)的默认初始值是未定义的(也就是一个随机数)。除了用作赋值操作的左操作数,其他任何使用未初始化变量的行为都是未定义的。如果试图拷贝或以其他方式访问该变量的值,此时会引发编译错误。
#include <iostream>
using namespace std;
int main()
{
int i;
double d;
bool b;
char c;
cout << "i = " << i << endl; // 报错
cout << "d = " << d << endl; // 报错
cout << "b = " << b << endl; // 报错
cout << "c = " << c << endl; // 报错
return 0;
}
4.类类型
类类型变量在定义时,如果没有提供初始化式,则会自动调用默认构造函数进行初始化(不论变量在哪里定义)。如果某类型没有默认构造函数,则定义该类型对象时必须提供显式初始化式。
在下面代码中,默认构造函数由编译器自动生成。
#include <iostream>
using namespace std;
class A
{
public:
void display() const
{
cout << data << endl;
}
private:
int data;
};
A a;
int main()
{
A b;
a.display();
b.display();
return 0;
}
编译器自动生成的默认构造函数使用与变量初始化相同的规则来初始化数据成员。在上面代码中,对象 a
在函数体外定义,其 int
类型数据成员被初始为 0
;对象 b
在函数体内定义,默认构造函数不会对其进行初始化(符合内置类型变量初始化规则),其中存放的都是随机值。同样,如果数据成员是类类型,则会调用相应的默认构造函数对数据成员进行初始化。
5.数组
定义数组时,如果没有显式提供初始化列表,则数组元素的自动化初始规则同普通变量一样:函数体外定义的内置类型数组,其元素初始为 0
;函数体内定义的内置类型数组,其元素无初始化;类类型数组无论在哪里定义,皆调用默认构造函数进行初始化,无默认构造函数则必须提供显式初始化列表。
如果定义数组时,仅提供了部分元素的初始列表,其剩下的数组元素,若是类类型则调用默认构造函数进行初始,若是内置类型则初始为 0
(不论数组定义位置)。
6.动态分配的数组
对于动态分配的数组,如果数组元素是内置类型,其元素无初始化;如果数组元素是类类型,依然调用默认构造函数进行初始化。可以使用跟在数组长度后面的一对空圆括号对数组元素做值初始化。
int* p1 = new int[10]; // p1指向的动态数组元素未初始化
int* p2 = new int[10](); // p2指向的动态数组元素被初始化为0
7.动态分配的单个对象
对于动态分配的单个对象,可使用直接初始化的语法规则在定义时显式初始化。如果不提供显式初始化式,动态创建的对象与在函数内部定义的变量初始化方式相同(即内置类型无初始化、类类型调用默认构造函数进行初始化)。