ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 一.默认初始化 1. **概念** 定义变量时没有指定初始值时进行的初始化操作。 + 没有(括号)初始化器或等号。 2. 初始化结果 + 内置变量的默认初始化的值取决于其作用域。 + 数组的每个元素同样执行默认初始化。 + 类类型的变量的默认初始化会调用无参构造函数。如果用户未指定,则非静态数据成员同样执行默认初始化。 ```c++ //执行了默认初始化 int i; //其中分配到的空间执行了默认初始化 int *p = new int; ``` > [03-] `new 类型()` 也是默认初始化 ## \[03+\][$]二.值初始化 1. **概念** 使用了括号进行初始化,但没有提供初始值的情况。 + 有括号(初始化器) + 没有初始值 2. 初始化结果 + 内置类型值初始化为0。 + 数组的每个元素同样执行值初始化。 + 类类型值初始化会调用相应无参构造函数。如果用户未指定,则非静态数据成员执行默认初始化。 + 定义标准库容器对象时,若只声明了容器大小,则其元素执行值初始化。 ```c++ //其中int() 产生的临时变量执行了值初始化 int i = int(); //其中new int() 分配到的空间执行了值初始化 int *p = new int(); //对,这也是值初始化 vector<int> v(10); ``` >[warning] 若初始化器没有参数,则编译器会将该表达式视为函数声明。 ```c++ //这是一个函数声明,而不是一个变量的定义 int i(); ``` ## 三.直接初始化 1. **概念** 使用括号进行初始化且指定了初始值。 + 有括号(初始化器) + 有初始值 ```c++ //i1是直接初始化 int i1(10); //[11+]i2也是直接初始化 int i2{10}; //v不是直接初始化,而是值初始化 vector<int> v(10); ``` ## 四.拷贝初始化 1. **时机** > 成员初始化列表不支持拷贝初始化。 - 使用等号进行初始化 - 使用一个对象初始化另一个对象 - 从函数返回一个对象 2. 结果 - 若使用一个同类型左值初始化对象,则调用 **拷贝构造函数**(内置类型是直接复制)。 - **\[17+\][17-的编译器可能支持]** 若使用同类型的右值(新标准为纯右值)初始化一个对象时,会发生 **复制消除** ,此时不会创建临时变量,而是直接用右边的表达式初始化左边的对象。 - 若等号左右两边类型不匹配,则调用 **转换构造函数**(内置类型直接隐式转换)。 >[warning] 以下示例请使用支持 C++17标准的编译器运行。 ```c++ #include <iostream> using namespace std; class Complex { private: double real_; double imaginary_; public: Complex() : real_(0), imaginary_(0) { cout << "已调用无参构造函数" << endl; } Complex(double real) : real_(real), imaginary_(0) { cout << "已调用普通构造函数" << endl; } Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) { cout << "已调用普通构造函数" << endl; } Complex(const Complex &old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; cout << "已调用拷贝构造函数" << endl; } Complex &operator=(const Complex &old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; cout << "已调用拷贝赋值函数" << endl; return *this; } Complex &operator=(const Complex &&old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; cout << "已调用移动赋值函数" << endl; return *this; } double get_real() { return this->real_; } double get_imaginary() { return this->imaginary_; } Complex &set_real(double new_val) { this->real_ = new_val; return *this; } Complex &set_imaginary(double new_val) { this->imaginary_ = new_val; return *this; } }; int main() { Complex a; //默认初始化,调用无参构造函数 Complex b(10, 10); //直接初始化,调用普通构造函数 Complex c = 10; //拷贝初始化,调用普通构造函数 Complex d = c; //拷贝初始化,调用拷贝构造函数 Complex e(a); //拷贝初始化,调用拷贝构造函数 Complex f = Complex(Complex(1, 2)); //拷贝初始化,且只初始化一次(发生了复制消除),相当于 `Complex f(1,2);`,调用普通构造函数 f = e; //拷贝赋值,调用拷贝赋值函数 f = Complex(3, 4); //移动赋值,先调用普通构造函数,再调用移动赋值函数 return 0; } ``` >[test] >已调用无参构造函数 >已调用普通构造函数 >已调用普通构造函数 >已调用拷贝构造函数 >已调用拷贝构造函数 >已调用普通构造函数 >已调用拷贝赋值函数 >已调用普通构造函数 >已调用移动赋值函数 >[warning] 以下示例可使用任意标准的编译器运行。 ```c++ #include <iostream> using namespace std; class Complex { private: double real_; double imaginary_; public: Complex() : real_(0), imaginary_(0) { cout << "已调用无参构造函数" << endl; } Complex(double real) : real_(real), imaginary_(0) { cout << "已调用普通构造函数" << endl; } Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) { cout << "已调用普通构造函数" << endl; } Complex(const Complex &old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; cout << "已调用拷贝构造函数" << endl; } Complex &operator=(const Complex &old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; cout << "已调用拷贝赋值函数" << endl; return *this; } double get_real() { return this->real_; } double get_imaginary() { return this->imaginary_; } Complex &set_real(double new_val) { this->real_ = new_val; return *this; } Complex &set_imaginary(double new_val) { this->imaginary_ = new_val; return *this; } }; int main() { Complex a; //默认初始化,调用无参构造函数 Complex b(10, 10); //直接初始化,调用普通构造函数 Complex c = 10; //拷贝初始化,调用普通构造函数 Complex d = c; //拷贝初始化,调用拷贝构造函数 Complex e(a); //拷贝初始化,调用拷贝构造函数 Complex f = Complex(1, 2); //拷贝初始化,可能先调用普通构造函数,再调用拷贝构造函数,也可能直接调用普通构造函数 f = e; //拷贝赋值,调用拷贝赋值函数 f = Complex(3, 4); //拷贝赋值,先调用普通构造函数,再调用拷贝赋值函数 return 0; } ``` >[test-gpp] > 已调用无参构造函数 > 已调用普通构造函数 > 已调用普通构造函数 > 已调用拷贝构造函数 > 已调用拷贝构造函数 > 已调用普通构造函数 > 已调用拷贝构造函数 > 已调用拷贝赋值函数 > 已调用普通构造函数 > 已调用拷贝赋值函数 >[test-vc] > 已调用无参构造函数 > 已调用普通构造函数 > 已调用普通构造函数 > 已调用拷贝构造函数 > 已调用拷贝构造函数 > 已调用普通构造函数 > 已调用拷贝赋值函数 > 已调用普通构造函数 > 已调用拷贝赋值函数 ## \[11+\][$]五.列表初始化 1. **概念** 用大括号进行初始化的情况。如数组和结构体的初始化。 2. 当类没有用户定义的构造函数,或某个构造函数参数类型为 `std::initializer_list` 时,该类可执行列表初始化。 ```c++ //v1直接列表初始化 std::vector v1{1,2,3,4,5}; //v2复制列表初始化 std::vector v2 = {1,2,3,4,5}; ```