首页IT科技c++11 类成员初始化(C++之列表初始化详解)

c++11 类成员初始化(C++之列表初始化详解)

时间2025-06-14 07:52:30分类IT科技浏览4140
导读:1、列表初始化的规则...

1            、列表初始化的规则

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

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

聚合类型可以进行直接列表初始化            ,那么什么是聚合类呢?

(1)类型是一个普通数组                  ,如int[5]      ,char[]            ,double[]等

(2)类型是一个类                  ,且满足以下条件:

没有用户声明的构造函数 没有用户提供的构造函数(允许显示预置或弃置的构造函数) 没有私有或保护的非静态数据成员 没有基类 没有虚函数 没有{}和=直接初始化的非静态数据成员 没有默认成员初始化器

文字难以琢磨可以看下面例子帮助理解:

// 有自定义的构造函数      ,不能列表初始化 class A { public: A(int, int){} int a; int b; int c; }; // 含有虚函数      ,不是聚合类 class B { public: virtual void func() {} int a; int b; }; // 有基类                  ,不是聚合类 class Base {}; class C : public Base { public: int a; int b; }; // 有等号初始化            ,不是聚合类 class D { public: int a; int b = 10; }; // 含有私有的非静态数据成员      ,不是聚合类 class E { public: int a; int b; private: int c; }; // 含有默认成员初始化器                  ,不是聚合类 class F { public: F() : a(0), b(0) {} int a; int b; };

2                  、列表初始化的优点

(1)高效            ,减少调用构造函数的次数

#include<iostream> using namespace std; class Data { public: // 无参构造函数 Data() {cout<<"This is Data constructor1"<<endl;} // 拷贝构造函数 Data(const Data&) {cout<<"This is Data constructor2"<<endl;} // 拷贝赋值构造函数 Data& operator=(const Data&) {cout<<"This is Data constructor3"<<endl;} }; // 低效写法 class Test1 { public: Test1(Data data) {m_data = data;} private: Data m_data; }; // 高效写法 class Test2 { public: Test2(Data data) : m_data(data){} private: Data m_data; }; // 更高效的写法 class Test3 { public: Test3(Data& data) : m_data(data){} private: Data m_data; }; int main() { Data a; cout<<"---------------THIS IS TEST1---------------"<<endl; Test1 t1(a); cout<<"---------------THIS IS TEST2---------------"<<endl; Test2 t2(a); cout<<"---------------THIS IS TEST3---------------"<<endl; Test3 t3(a); return 0; } /* 输出结果: This is Data constructor1 ---------------THIS IS TEST1--------------- This is Data constructor2 This is Data constructor1 This is Data constructor3 ---------------THIS IS TEST2--------------- This is Data constructor2 This is Data constructor2 ---------------THIS IS TEST3--------------- This is Data constructor2 (1)对于TEST1,没有使用列表初始化                  ,所以其私有变量m_data是通过调用Data()定义的                  ,所以会出现“This is Data constructor1            ”,而“This is Data constructor2                  ”是在发生在参数传递调用的拷贝构造            ,最 后“m_data = data      ”会发生拷贝赋值                  ,从而调用“This is Data constructor3            ” (2)对于TEST2      ,“This is Data constructor2                  ”也是在发生在参数传递调用的拷贝构造            ,而另外一次调用是 发生在列表初始化“Test2(Data data) : m_data(data){}      ” (3)对于TEST3                  ,则是TEST3的构造函数中参数使用了引用      ,就避免了参数传递而调用的拷贝构造      ,所以只有一次 调用拷贝构造是发生在列表初始化的时候 */

(2) 防止类型窄化                  ,避免精度丢失的隐式类型转化

C++11可使用 explicit 关键字对单参数的构造函数进行声明            ,让编译器无法进行隐式类型转换      ,但仅限于单参数或者其他参数有默认值的情况下使用                  。而列表初始化是禁止避免精度丢失的隐式类型转化                  ,不像 explicit 禁止所有的隐式类型转换

int main() { // 浮点型到整型的转换 int a = 1.2; // ok int b = {1.2}; // error // 整型到浮点型的转换 float c = 1e70; // ok float d = {1e70}; // error // char的枚举类型 const int i = 1000; const int j = 65; char k = i; // ok char l = {i}; // error char m = j; // ok            ,m为A char m = {j}; // ok,因为是const类型                  ,这里如果去掉const属性                  ,也会报错 }

(3)可以使用初始化列表接受任意长度的参数

std::initializer_list,它可以接收任意长度的初始化列表            ,但是里面必须是相同类型T                  ,或者都可以转换为T

class Test { public: Test(std::initializer_list<int> list) { for (auto iter = list.begin(); iter != list.end(); ++iter) { vec.push_back(*iter); } } private: std::vector<int> vec; };

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
计算机科学考证难吗知乎(【ChatGPT】参加计算机科学考试(GPT-4对比GPT-3.5)) 什么叫伪原创文章(伪原创文章在线检测软件,助力你的内容创作!)