当前位置: 首页 > article >正文

【C++】构造函数冒号后面的初始化列表使用小括号( )和大括号{ }的区别(回子的四种写法)

1、创建对象时,使用小括号( )和大括号{ }的区别

1)内置类型的初始值,以下三种方法没有区别

int x(0); 
int y = 0;
int z{0}; 

2)自定义类型的赋值

Widget w1;       调用默认构造函数
Widget w2 = w1;  调用拷贝构造函数,不是赋值操作
w1 = w2;         调用operator=函数,是赋值操作

3)类内成员的默认初始值
类内成员的默认初始值:可以使用大括号、等号;不可以使用小括号

class Widget {
  ...
private:
  int x{ 0 };   x的默认初始值为0
  int y = 0;    同上
  int z( 0 );   报错
}

注意:当大括号用于类内成员的默认初始值时,如果初始值存在丢失信息的风险,则编译器将报错:

doubel ld = 3.14;
int a {ld};    报错,存在信息丢失风险
int b (ld);    正确

4)声明对象还是创建对象
调用带参构造函数,可以使用如下方法:

Widget w1(10); 

如果想调用午餐构造函数时,不可以使用下面的方法,因为这会被编译器理解为:声明了个函数,而不是创建对象

Widget w2()

正确的方法:

Widget w2; 

或者使用大括号

Widget w2{}; 

2、大括号和std::initializer_list

大括号这么牛逼,统一都使用大括号不就得了。实际情况不是这么理想。这很C++……

1)先看使用 std::initializer_list 的情况(小括号和大括号行为一致)
大括号初始化的缺点是它有时会显现令人惊讶的的行为。这些行为的出现是因为与std::initializer_list混淆了。在构造函数中,只

class Widget {
public:
  Widget(int i, bool b);
  Widget(int i, double d);
  ...
};

Widget w1(10, true);   调用第一个构造函数
Widget w2{10, true};   调用第一个构造函数
Widget w3(10, 5.0);    调用第二个构造函数
Widget w4{10, 5.0};    调用第二个构造函数

2)形参带有std::initializer_list
如果构造函数的形参带有std::initializer_list,调用构造函数时大括号初始化语法会强制使用带 std::initializer_list 参数的重载构造函数:

class Widget {
public:
  Widget(int i, bool b);
  Widget(int i, double d);
  Widget(std::initializer_list<long double> il);
  ...
};
Widget w1(10, true);    使用圆括号,调用第一个构造函数
Widget w2{10, true};    使用大括号,强制调用第三个构造函数,10true被转换为long double                    
Widget w3(10, 5.0);     使用圆括号,调用第二个构造函数
Widget w4{10, 5.0};     使用大括号,强制调用第三个构造函数,105.0被转换为long double

3)拷贝构造和赋值构造也受带有std::initializer_list的构造函数的影响

class Widget {
public:
  Widget(int i, bool b);
  Widget(int i, double d);
  Widget(std::initializer_list<long double> il);
  operator float() const;   // 支持隐式转换为float类型
  ...
};

Widget w5(w4);    使用圆括号,调用拷贝构造函数
Widget w6{w4};    使用大括号,调用第三个构造函数,原因是先把w4转换为float,再把float转换为long dobule
Widget w7(std::move(m4));  使用圆括号,调用移动构造函数
Widget w8{std::move(m4)};  使用大括号,调用第三个构造函数,理由同w6

4)即使参数数量不匹配,照样优先使用 std::initializer_list 的构造函数,

class Widget {
public:
  Widget(int i, bool b);
  Widget(int i, double d);
  Widget(std::initializer_list<bool> il);  // long double 改为 bool
  ...
};

Widget w{10, 5.0}; 

报错,因为参数个数不匹配,编译器会忽略另外两个构造函数(第二个还是参数精确匹配的!)

5)只有当大括号内的值无法转换为std::initializer_list元素的类型时,编译器才会使用正常的重载选择方法:

class Widget {
public:
  Widget(int i, bool b);
  Widget(int i, double d);
  Widget(std::initializer_list<std::string> il);  // bool 改为 std::string
  ...
};

Widget w1(10, true);   使用圆括号,调用第一个构造函数
Widget w2{10, true};   使用大括号,不过调用第一个构造函数,因为无法转换为string
Widget w3(10, 5.0);    使用圆括号,调用第二个构造函数
Widget w4{10, 5.0};    使用大括号, 不过调用第二个构造函数,因为无法转换为string

6)只有空括号可以不强制匹配 std::initializer_list 构造函数

class Widget {
public:
  Widget();
  Widget(std::initializer_list<int> il);
  ...
};

Widget w1;     调用默认构造函数
Widget w2{};   调用默认构造函数

7)小括号( )和大括号{ }初始化容器时的却

std::vector v1(10, 20); // 使用不带std::initializer_list的构造函数,创建10个元素的vector,每个元素的初始值为20
std::vector v2{10, 20}; // 使用带std::initializer_list的构造函数, 创建2个元素的vector,元素值为10和20

原因是:
std::vector中有一个可以指定容器的大小和容器内元素的初始值的不带std::initializer_list构造函数,但它也有一个可以指定容器中元素值的带std::initializer_list函数。


http://www.kler.cn/news/368984.html

相关文章:

  • Windows/Linux(服务器)查看显卡的名称
  • 《手写Spring渐进式源码实践》实践笔记(第十一章 AOP-基于JDK、Cglib实现对象动态代理)
  • 【我的创作纪念日1024】
  • 从0到1,用Rust轻松制作电子书
  • 2024年信息化管理与计算技术研讨会 (ICIMCT 2024)--分会场
  • 100种算法【Python版】第10篇——深度优先搜索
  • 高效思维管理:2024年必备在线思维导图软件!
  • C++初阶学习第八弹--深入解析vector的使用
  • 防火墙防御体系结构类型
  • uniapp开发小程序【点击头像实现更改头像、上传头像】
  • 【Linux】MyCat分库分表|读写分离
  • docker的持久化
  • QT:MaintenanceTool 模块安装工具
  • 快速对比:Django、Spring Boot、Node.js 和 PHP
  • 软件测试学习笔记丨Selenium学习笔记:元素定位与操作
  • Matlab的安装和破解
  • 【Pip】深入理解 Python 中的 pip 虚拟环境
  • App测试环境部署
  • 利用Spring Boot框架开发酒店住宿管理应用
  • 【论文阅读】jina-embeddings-v3: Multilingual Embeddings With Task LoRA
  • ChatGPT:从发布到全球大热,仅用一年多的传奇之旅
  • 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-23
  • 游戏服务器被攻击有办法防护吗
  • 51单片机之蜂鸣器驱动
  • MySQL笔试面试题之AI答(3)
  • jvm虚拟机介绍