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

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

时间2025-09-19 09:11:01分类IT科技浏览5642
导读: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
如何在js中创建对象(Javascript中创建元素的三种方式以及区别)