05 C++11 初始化列表

声明:本篇文章引用自以下两篇文章

  1. https://mp.weixin.qq.com/s/wpV4K0aJS9l3ilk4nuurQA
  2. https://subingwen.cn/cpp/list-init/#3-2-%E4%BD%9C%E4%B8%BA%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0
    欢迎大家关注支持原作者!

在C++11中可以直接在变量名后面加上初始化列表来进行对象的初始化。

struct A {
public:
   A(int) {}
private:
    A(const A&) {}
};
int main() {
   A a(123);
   A b = 123; // error
   A c = { 123 };
   A d{123}; // c++11
   
   int e = {123};
   int f{123}; // c++11
   
   return 0;
}

列表初始化也可以用在函数的返回值上

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
    Person(int id, string name)
    {
        cout << "id: " << id << ", name: " << name << endl;
    }
};

Person func()
{
    return { 9527, "华安" };
}

int main(void)
{
    Person p = func();
    return 0;
}

列表初始化的一些规则:
首先说下聚合类型可以进行直接列表初始化,这里需要了解什么是聚合类型:

  1. 类型是一个普通数组,如int[5],char[],double[]等
  2. 类型是一个类,且满足以下条件:
  • 没有用户声明的构造函数
  • 没有用户提供的构造函数(允许显示预置或弃置的构造函数)
  • 没有私有或保护的非静态数据成员
  • 没有基类
  • 没有虚函数
  • 没有{}和=直接初始化的非静态数据成员
  • 没有默认成员初始化器
struct A {
   int a;
   int b;
   int c;
   A(int, int){}
};
int main() {
   A a{1, 2, 3};// error,A有自定义的构造函数,不能列表初始化
}

上述代码类A不是聚合类型,无法进行列表初始化,必须以自定义的构造函数来构造对象。

struct A {
int a;
   int b;
   virtual void func() {} // 含有虚函数,不是聚合类
};

struct Base {};
struct B : public Base { // 有基类,不是聚合类
int a;
   int b;
};

struct C {
   int a;
   int b = 10; // 有等号初始化,不是聚合类(C++14中已支持此操作)
};

struct D {
   int a;
   int b;
private:
   int c; // 含有私有的非静态数据成员,不是聚合类
};

struct E {
int a;
   int b;
   E() : a(0), b(0) {} // 含有默认成员初始化器,不是聚合类
};

上面列举了一些不是聚合类的例子,对于一个聚合类型,使用列表初始化相当于对其中的每个元素分别赋值;对于非聚合类型,需要先自定义一个对应的构造函数,此时列表初始化将调用相应的构造函数。

std::initializer_list

在 C++ 的 STL 容器中,可以进行任意长度的数据的初始化,使用初始化列表也只能进行固定参数的初始化,如果想要做到和 STL 一样有任意长度初始化的能力,可以使用 std::initializer_list 这个轻量级的类模板来实现。
先来介绍一下这个类模板的一些特点:

  1. 它是一个轻量级的容器类型,内部定义了迭代器 iterator 等容器必须的概念,遍历时得到的迭代器是只读的。
  2. 对于 std::initializer_list 而言,它可以接收任意长度的初始化列表,但是要求元素必须是同种类型 T
  3. 在 std::initializer_list 内部有三个成员接口:size(), begin(), end()。
  4. std::initializer_list 对象只能被整体初始化或者赋值。

作为普通函数参数

如果想要自定义一个函数并且接收任意个数的参数(变参函数),只需要将函数参数指定为 std::initializer_list,使用初始化列表 { } 作为实参进行数据传递即可。

#include <iostream>
#include <string>
using namespace std;

void traversal(std::initializer_list<int> a)
{
    for (auto it = a.begin(); it != a.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main(void)
{
    initializer_list<int> list;
    cout << "current list size: " << list.size() << endl;
    traversal(list);

    list = { 1,2,3,4,5,6,7,8,9,0 };
    cout << "current list size: " << list.size() << endl;
    traversal(list);
    cout << endl;
    
    list = { 1,3,5,7,9 };
    cout << "current list size: " << list.size() << endl;
    traversal(list);
    cout << endl;

    
    // 直接通过初始化列表传递数据 //
    
    traversal({ 2, 4, 6, 8, 0 });
    cout << endl;

    traversal({ 11,12,13,14,15,16 });
    cout << endl;


    return 0;
}

作为构造函数参数

自定义的类如果在构造对象的时候想要接收任意个数的实参,可以给构造函数指定为 std::initializer_list 类型,在自定义类的内部还是使用容器来存储接收的多个实参。

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

class Test
{
public:
    Test(std::initializer_list<string> list)
    {
        for (auto it = list.begin(); it != list.end(); ++it)
        {
            cout << *it << " ";
            m_names.push_back(*it);
        }
        cout << endl;
    }
private:
    vector<string> m_names;
};

int main(void)
{
    Test t({ "jack", "lucy", "tom" });
    Test t1({ "hello", "world", "nihao", "shijie" });
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值