第6课 列表初始化_统一初始化

Posted 浅墨浓香

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第6课 列表初始化_统一初始化相关的知识,希望对你有一定的参考价值。

1. 统一初始化(Uniform Initialization)

(1)在C++11之前,很多程序员特别是初学者对如何初始化一个变化或对象的问题很容易出现困惑。因为可以用小括号、大括号或赋值操作符等多种方式进行初始化

(2)基于这个原因,C++11引入了“统一初始化”的概念。这意味着我们可以使用{}这种通用的语法在任何需要初始化的地方。

【实例分析】初始化列表

#include <iostream>
#include <vector>
#include <map>
using namespace std;

//编译选项:g++ -std=c++11 test1.cpp

struct Test
{
    int x;
    int y;
} test  {123, 321}; //等价于test = {123,321}

int main()
{
    int i;   //未初始化
    int j{}; //j被初始化为0
    int* p;  //未初始化
    int* q{}; //j被初始化为nullptr
    
    int* a = new int{123}; //等价于int* x=new int(123);
    double b = double{12.12}; //等价于double(12.12)产生一个临时对象,再拷贝初始化
    int* arr = new int[3]{1, 2, 3}; //C++11中新增的初始化堆上数组的方式
    std::map<std::string, int> mm {{"2", 1},{"2", 2}, {"3", 3}}; //相当于map<string,int> mm = {...};
        
    cout << test.x << endl;
    cout << test.y << endl;
    
    return 0;
}

2. 列表初始化的使用细节

(1)引入初始化列表(initializer-list)出现的一些模糊概念

//x,y究竟为0,0还是123,321?
struct A
{
  int x;
  int y;

  A(int,int):x(0), y(0){} //非聚合类型,使用{}初始化时会调用相应的构造函数
} a = {123, 321};  //a.x=0, a.y=0

(2)聚合类型的定义

  ①类型是一个普通类型的数组(如int[10]、char[]、long[2][3])

  ②类型是一个类(class、struct或union),且:

    A.无基类、无虚函数以及无用户自定义的构造函数。

    B.无private或protected的普通数据成员(即非静态数据成员)。

    C.不能有{}和=直接初始化的非静态数据成员(“就地初始化”)

【实例分析】聚合类型与非聚合类型的初始化

#include <iostream>
using namespace std;

struct Base{};

//聚合类型的定义
struct Foo : public Base //不能有基类
{
private:
    double z;      //不能有private的普通成员
    static int k;  //ok,但必须在类外用int Foo::k = 0的方式初始化
public:
    Foo(int x, int y, double z):x(x),y(y),z(z) //不能有构造函数!
    {
        cout<< "Foo(int x, int y, double z)" << endl;
    } 
    
    Foo(const Foo& foo)  //不能有构造函数!
    {
        this->x = foo.x;
        this->y = foo.y;
        this->z = foo.z;
        
        cout<< "Foo(const Foo& foo)" << endl;
    }
    
    int x;
    int y; //不能通过int y=0;或int y{0}来"就地初始化"
    virtual void F(){}; //不能有虚函数!
        
};

Foo f1(1, 2, 3.0);     //直接调用构造函数初始化
Foo f2{4, 5, 6.0};     //由于Foo是个非聚合类型,使用{}时会调用相应的构造函数来初始化。
Foo f3 = {7, 8, 9.0};  //非聚合类型会调用构造函数来初始化

int main()
{
    cout << a.x << endl;
    cout << a.y << endl;
    return 0;
}
/*输出结果:
Foo(int x, int y, double z)
Foo(int x, int y, double z)
Foo(int x, int y, double z)
*/

(3)注意事项

  ①聚合类型的定义是非递归的。简单来说,当一个类的普通成员是非聚合类型时,这个类也有可能是聚合类型,也就是说可以直接用列表初始化。

  ②对于一个聚合类型可以直接使用{}进行初始化,这时相当于对其中每个元素分别赋值;而对于非聚合类型,则需要先自定义一个合适的构造函数才能使用{}进行初始化,此时使用初始化列表将调用它对应的构造函数。

以上是关于第6课 列表初始化_统一初始化的主要内容,如果未能解决你的问题,请参考以下文章

第21课 可变参数模板_展开参数包

第20课.初始化列表

第20课 - 初始化列表的使用

第46课 继承中的构造与析构

第46课 继承中的构造与析构

第23课 可变参数模板_Optional和Lazy类的实现