在 C++ 中,初始化是指为变量或对象赋予初始值的过程。不同类型的实体(如基本类型、数组、类对象等)具有不同的初始化方式。本文将对 C++ 的初始化方式进行一次总结。
基础类型初始化(int, double, char 等)
默认初始化
- a. 局部变量默认值为未定义(可能是0,也可能是任何其他内存数据);
- b. 全局变量,静态变量默认为零值。
// 局部变量:未定义值;
// 全局变量:默认0
int a;
// 静态变量:默认0.0
static double b;
2.直接初始化
使用括号 () 赋值(C++98 起支持)。
int x(10);
char c('a');
double d(3.14);
3.拷贝初始化
使用等号 = 赋值(本质是调用拷贝构造函数)。
int y = 20;
char ch = 'b';
4.列表初始化(C++11 起)
使用花括号 {} 赋值(支持防止窄化转换,更安全)。
// 正确
int m{30};
char k{'c'};
// 错误:double 转 int 是窄化转换,编译报错
// int n{3.14};
5.值初始化
对无初始值的变量强制初始化为零(常用于动态分配)。
// z = 0
int z{};
// w = 0.0
double w{};
// 动态分配的 int 初始化为 0
int* ptr = new int();
数组初始化
1.默认初始化
全局/静态数组默认零初始化,局部数组未初始化(值不确定)。
// 局部:未定义;全局:全0
int arr1[5];
// 全0
static int arr2[3];
2.列表初始化(C 风格)
用 {} 赋值,未指定的元素默认零初始化。
// 前3个为1,2,3,后2个为0
int arr3[5] = {1, 2, 3};
// 自动推导长度为6(含'�')
char str1[] = "hello";
3.列表初始化(C++11 起,省略等号)
int arr4[3]{4, 5, 6};
// 显式添加结束符
char str2[]{'h', 'i', '�'};
4.动态数组初始化(C++11 起)
动态分配数组时支持列表初始化。
int* arr5 = new int[3]{7, 8, 9};
类与结构体初始化
1.默认构造函数初始化
若类定义了默认构造函数,可直接声明对象。
class Person
{
public:
// 默认构造函数
Person() : _age(0) {}
public:
int _age;
};
// 调用默认构造函数,_age=0
Person p1;
2.带参数的构造函数初始化(直接初始化)
class Person
{
public:
// 默认构造函数
Person() : _age(0) {}
public:
int _age;
};
// 直接初始化,age=20
Person p2(20);
3.拷贝初始化(调用拷贝构造函数)
// 拷贝初始化(需拷贝构造函数)
Person p3 = p2;
4.列表初始化(C++11 起,适用于聚合类或带构造函数的类)
- a. 聚合类(无用户定义构造函数、无私有/保护成员等)可直接用列表初始化成员。
struct Point
{
int _x;
int _y;
};
// x=10, y=20
Point p4{10, 20};
- b.带构造函数的类:若构造函数支持,可通过列表传递参数。
class Person
{
public:
Person(int a, string n) : _age(a), _name(n) {}
public:
int _age;
string _name;
};
// 等价于 Person p5(25, "Alice")
Person p5{25, "Alice"};
5.成员初始化列表(构造函数内初始化成员)
“成员初始化列表”是 C++ 中构造函数的一种特殊语法,用于在构造函数体执行之前初始化类的成员变量。其格式为在构造函数参数列表后使用冒号 : 引出,多个成员的初始化用逗号 , 分隔(例如下方示例中的 _id(i), _name(n))。
成员初始化列表具有以下好处:
- a.效率更高:直接初始化成员变量,避免了先调用默认构造函数再赋值的过程(尤其对于没有默认构造函数的类类型成员,必须使用初始化列表)。
- b.必要性:常量成员(const)、引用成员(&)以及没有默认构造函数的类类型成员,必须通过成员初始化列表进行初始化,无法在构造函数体内赋值。
class Student
{
public:
// 成员初始化列表
Student(int i, string n) : _id(i), _name(n) {}
public:
int _id;
string _name;
};
容器初始化(STL 容器,如 vector、string 等)
1.默认初始化
// 空向量
vector<int> v1;
// 空字符串
string s1;
2.带参数初始化
// 5个元素,每个为0
vector<int> v2(5, 0);
// "aaa"
string s2(3, 'a');
3.列表初始化(C++11 起)
// 元素为1,2,3,4
vector<int> v3{1, 2, 3, 4};
// "hello"
string s3{"hello"};
// 键值对初始化
map<int, string> m{{1, "one"}, {2, "two"}};
4.范围初始化
用其他容器的范围初始化。
// 复制v3的元素
vector<int> v4(v3.begin(), v3.end());
指针与动态内存初始化
1.空指针初始化(C++11 起推荐 nullptr)
// 空指针(优于 NULL,避免类型混淆)
int* p1 = nullptr;
// C风格空指针(本质是0)
char* p2 = NULL;
2.指向已有变量
int x = 10;
// p3指向x
int* p3 = &x;
3.动态分配初始化(new 操作符)
// 动态分配int并初始化为100
int* p4 = new int(100);
// 动态数组初始化(C++11起)
int* p5 = new int[3]{1, 2, 3};
引用初始化
引用必须在声明时初始化,且一旦初始化后不能更改指向。
int a = 5;
// 引用a
int& ref1 = a;
// 常量引用可绑定字面量
const int& ref2 = 10;
C++11 后的新特性
1.{} 统一初始化
用 {} 统一各类初始化(减少歧义,支持防止窄化转换)。
int a{5};
vector<int> v{1, 2, 3};
Person p{20, "Bob"};
2.列表初始化器(initializer_list)
允许函数接收任意长度的同类型参数(如 STL 容器的构造函数)。
void Print(initializer_list<int> list)
{
for (auto x : list)
{
cout << x << " ";
}
}
// 调用时传递列表
Print({1, 2, 3, 4});
总结
- 1.C++98 主要支持:默认初始化、直接初始化(使用圆括号 ())、拷贝初始化(使用赋值运算符 =)。
- 2.C++11 新增:列表初始化(使用花括号 {})、nullptr 关键字、std::initializer_list 类型等特性,统一了初始化语法并增强了类型安全性。
- 3.列表初始化({})是推荐的现代 C++ 编程方式,尤其适用于防止窄化转换和保持统一的代码风格。
附:参考示例
#include <initializer_list>
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;
// 定义测试类(用于演示类的初始化)
class MyClass
{
public:
// 默认构造函数
MyClass()
: _a(0), _b(0.0), _c("default")
{
cout << "调用默认构造函数" << endl;
}
// 带参数的构造函数
MyClass(int a, double b, string c)
: _a(a), _b(b), _c(c)
{
cout << "调用带参构造函数" << endl;
}
// 拷贝构造函数
MyClass(const MyClass& other)
: _a(other._a), _b(other._b), _c(other._c)
{
cout << "调用拷贝构造函数" << endl;
}
// 支持initializer_list的构造函数(C++11起)
MyClass(initializer_list<int> list)
{
cout << "调用initializer_list构造函数" << endl;
_a = *list.begin(); // 取列表第一个元素
_b = 0.0;
_c = "from list";
}
public:
int _a;
double _b;
string _c;
};
// 聚合类(无用户定义构造函数,用于演示聚合初始化)
struct Aggregate
{
int _x;
double _y;
string _z;
};
// 测试initializer_list参数的函数(C++11起)
void PrintList(initializer_list<string> items)
{
for (const auto& item : items)
{
cout << item << " ";
}
cout << endl;
}
int main()
{
// 基础类型初始化
cout << "----- 基础类型初始化 -----" << endl;
// 1. 默认初始化(局部变量未定义,全局变量默认0)
// 局部变量:值未定义(危险)
int basicDefault;
cout << "局部变量默认初始化: "
<< basicDefault
<< endl;
// 静态变量:默认0
static int staticDefault;
cout << "静态默认初始化: "
<< staticDefault
<< endl;
// 2. 直接初始化(C++98起)
int direct(10);
char directChar('A');
cout << "直接初始化: "
<< direct << ", "
<< directChar
<< endl;
// 3. 拷贝初始化(C++98起)
int copy = 20;
double copyDouble = 3.14;
cout << "拷贝初始化: "
<< copy << ", "
<< copyDouble
<< endl;
// 4. 列表初始化(C++11起,防止窄化转换)
int listInit{30};
// 错误:窄化转换(double→int)
// int narrow{3.14};
cout << "列表初始化: "
<< listInit << endl;
// 5. 值初始化(强制零初始化)
// 等价于int valueInit = 0
int valueInit{};
double valueDouble{};
cout << "值初始化: "
<< valueInit << ", "
<< valueDouble << endl;
// 数组初始化
cout << "n----- 数组初始化 -----" << endl;
// 1. 默认初始化
// 局部数组:值未定义
int arrDefault[3];
cout << "局部数组默认初始化: "
<< arrDefault[0] << ","
<< arrDefault[1] << endl;
// 静态数组:默认全0
static int staticArr[3];
cout << "静态数组默认初始化: "
<< staticArr[0] << ","
<< staticArr[1] << endl;
// 2. C风格列表初始化(带等号)
// 未指定元素默认0
int arrCStyle[5] = {1, 2, 3};
cout << "C 风格数组初始化: ";
for (int i : arrCStyle)
{
cout << i << " ";
}
cout << endl;
// 3. C++11列表初始化(省略等号)
int arrCPP11[3]{4, 5, 6};
cout << "C++11数组初始化: ";
for (int i : arrCPP11)
{
cout << i << " ";
}
cout << endl;
// 4. 动态数组初始化(C++11起支持列表)
int* dynArr = new int[4]{7, 8, 9, 10};
cout << "动态数组初始化: ";
for (int i = 0; i < 4; ++i)
{
cout << dynArr[i] << " ";
}
cout << endl;
delete[] dynArr;
// 类与结构体初始化
cout << "n----- 类与结构体初始化 -----" << endl;
// 1. 类的默认构造函数初始化
MyClass objDefault;
cout << "默认构造: "
<< objDefault._a << ","
<< objDefault._b << endl;
// 2. 类的直接初始化(带参构造)
MyClass objDirect(1, 3.14, "direct");
cout << "直接初始化: "
<< objDirect._a << ","
<< objDirect._b << endl;
// 3. 类的拷贝初始化
MyClass objCopy = objDirect; // 调用拷贝构造
cout << "拷贝初始化: "
<< objCopy._a
<< ","
<< objCopy._c
<< endl;
// 4. 类的列表初始化(匹配带参构造)
// 等价于MyClass(2,6.28,"list")
MyClass objList{2, 6.28, "list"};
cout << "类列表初始化: "
<< objList._a << ","
<< objList._c << endl;
// 5. 类的initializer_list初始化(C++11起)
// 匹配initializer_list构造
MyClass objInitList{100, 200, 300};
cout << "initializer_list初始化: "
<< objInitList._a
<< endl;
// 6. 聚合类初始化(无构造函数,直接初始化成员)
Aggregate agg{10, 20.5, "aggregate"};
cout << "聚合类初始化: "
<< agg._x << ","
<< agg._y << ","
<< agg._z << endl;
// 7. 成员初始化列表(在类构造函数中,见MyClass定义)
// STL容器初始化
cout << "n----- STL容器初始化 -----" << endl;
// 1. 默认初始化
vector<int> vecDefault;
cout << "vector默认大小: "
<< vecDefault.size() << endl;
// 2. 带参数初始化
// 5个元素,值为0
vector<int> vecParam(5, 0);
// 3个'x'
string strParam(3, 'x');
cout << "vector带参初始化: "
<< vecParam.size()
<< ", string带参: "
<< strParam << endl;
// 3. 列表初始化(C++11起)
vector<int> vecList{1, 2, 3, 4};
map<int, string> mapList{{1, "one"}, {2, "two"}};
cout << "vector列表: "
<< vecList[2]
<< ", map列表: "
<< mapList[2]
<< endl;
// 4. 范围初始化
vector<int> vecRange(vecList.begin() + 1, vecList.end());
cout << "范围初始化vector: "
<< vecRange[0]
<< "," << vecRange[1]
<< endl;
// 指针与动态内存初始化
cout << "n----- 指针初始化 -----" << endl;
// 1. 空指针初始化(C++11起推荐nullptr)
int* nullPtr1 = nullptr;
char* nullPtr2 = NULL; // C风格(本质是0)
cout << "空指针判断: "
<< (nullPtr1 == nullptr ? "nullptr" : "not null")
<< " "
<< (nullPtr2 == NULL ? "NULL" : "not null")
<< endl;
// 2. 指向已有变量
int var = 100;
int* ptrToVar = &var;
cout << "指向变量的指针: "
<< *ptrToVar << endl;
// 3. 动态分配初始化
// 初始化单个int
int* dynInt = new int(200);
// 动态对象列表初始化
MyClass* dynObj = new MyClass{3, 9.42, "dynamic"};
cout << "动态int: "
<< *dynInt
<< ", 动态对象: "
<< dynObj->_c
<< endl;
delete dynInt;
delete dynObj;
// 引用初始化
cout << "n----- 引用初始化 -----" << endl;
int refVar = 50;
// 引用必须初始化,绑定到ref_var
int& ref = refVar;
// 常量引用可绑定字面量
const int& constRef = 100;
cout << "引用: "
<< ref << ", 常量引用: "
<< constRef << endl;
// initializer_list函数参数
cout << "n----- initializer_list函数参数 -----" << endl;
// 传递列表参数
PrintList({"apple", "banana", "cherry"});
return 0;
}
附:参考示例输出
----- 基础类型初始化 -----
局部变量默认初始化: 32156
静态默认初始化: 0
直接初始化: 10, A
拷贝初始化: 20, 3.14
列表初始化: 30
值初始化: 0, 0
----- 数组初始化 -----
局部数组默认初始化: 0,0
静态数组默认初始化: 0,0
C 风格数组初始化: 1 2 3 0 0
C++11数组初始化: 4 5 6
动态数组初始化: 7 8 9 10
----- 类与结构体初始化 -----
调用默认构造函数
默认构造: 0,0
调用带参构造函数
直接初始化: 1,3.14
调用拷贝构造函数
拷贝初始化: 1,direct
调用带参构造函数
类列表初始化: 2,list
调用initializer_list构造函数
initializer_list初始化: 100
聚合类初始化: 10,20.5,aggregate
----- STL容器初始化 -----
vector默认大小: 0
vector带参初始化: 5, string带参: xxx
vector列表: 3, map列表: two
范围初始化vector: 2,3
----- 指针初始化 -----
空指针判断: nullptr NULL
指向变量的指针: 100
调用带参构造函数
动态int: 200, 动态对象: dynamic
----- 引用初始化 -----
引用: 50, 常量引用: 100
----- initializer_list函数参数 -----
apple banana cherry
说明
- 1.兼容性:标注了 C++11 的特性(如 {} 列表初始化、nullptr、std::initializer_list),其余部分兼容 C++98 及更早版本。
- 2.安全性:列表初始化({})会阻止窄化转换(例如 int a{3.14}; 会导致编译错误),比 () 更安全。
- 3.聚合类:无用户定义构造函数、无私有或保护成员的类或结构体,可以直接用 {} 初始化成员。
- 4.引用特性:引用必须在声明时初始化,且一旦绑定后不能更改指向(与指针不同)。
- 5.动态内存:new 操作符在 C++11 后支持通过列表初始化动态数组(例如 new int[3]{1, 2, 3})。

