第8课 列表初始化(3)_防止类型收窄、explicit关键字
1. 防止类型收窄
(1)类型收窄:指的是导致数据内容发生变化或者精度丢失的隐式类型转换。
(2)类型收窄的几种情况:
①从浮点数隐式转换为整型数,如int i=2.2;
②从高精度浮点数隐式转换为低精度浮点数。如从long double转double或float。
③从整型数隐式转换为浮点数,并且超出浮点数的表示范围,如float=(unsigned long Long)-1,注意这表示将-1先强制转换为unsigned long long,再隐式转换为float。
④从整型数隐式转换为长度较短的整型数,并且超出其表示范围。如char x=65536。
(3)在C++98/03中,类型收窄编译器不会报错,而C++11中可以通过列表初始化来检查及防止类型收窄。
【编程实验】防止类型收窄
#include <iostream>
#include <vector>
using namespace std; int main()
{
int x1(5.3); //ok,x1=5
int x2 = 5.3; //ok,x2=5
int x3 {5.3}; //error:narrowing,gcc给的是warning
int x4 = {5.3};//同上
char c1{}; //ok
char c2{};//error:narrowing,gcc给的是warning
std::vector<int> v1{,,,,}; //ok
std::vector<int> v2{,,,,5.6}; //error:narrowing,gcc给的是warning float fa = 1e40; //ok,double->float
float fb = {1e40};//error,double->float,超过float能表示的范围
float fc = (unsigned long long)-; //将-1(0xFFFFFFFF)强转,再隐式转成float
float fd = {(unsigned long long)-}; //error
float fe = (unsigned long long); //将1强转,再隐式转成float
float ff = {(unsigned long long)}; //ok const int x = , y = ; //注意x,y被const修饰
char c = x; //ok
char d = {x};//error
char e = y; //ok
char f = {y};//ok。如果y为int型,则该行会出错。但由于加了const并且值为1。编译器
//认为这样的转换是安全的。 return ;
}
/*
*******************gcc上的测试结果*********************
e:\Study\C++11\8>g++ -std=c++11 test1.cpp
test1.cpp: In function 'int main()':
test1.cpp:9:13: error: narrowing conversion of '5.2999999999999998e+0' from 'double' to 'int' inside { } [-Wnarrowing]
test1.cpp:10:15: error: narrowing conversion of '5.2999999999999998e+0' from 'double' to 'int' inside { } [-Wnarrowing]
test1.cpp:12:15: error: narrowing conversion of '99999' from 'int' to 'char' inside { } [-Wnarrowing]
test1.cpp:14:33: error: narrowing conversion of '5.5999999999999996e+0' from 'double' to 'int' inside { } [-Wnarrowing]
test1.cpp:17:18: error: narrowing conversion of '1.0e+40' from 'double' to 'float' inside { } [-Wnarrowing]
test1.cpp:19:36: error: narrowing conversion of '18446744073709551615ull' from 'long long unsigned int' to 'float' inside { } [-Wnarrowing]
test1.cpp:24:11: warning: overflow in implicit constant conversion [-Woverflow]
test1.cpp:25:13: error: narrowing conversion of '1024' from 'int' to 'char' inside { } [-Wnarrowing] *******************vc2015上的测试结果*********************
test1.cpp(9): error C2397: 从“double”转换到“int”需要收缩转换
test1.cpp(10): error C2397: 从“double”转换到“int”需要收缩转换
test1.cpp(12): error C2397: 从“int”转换到“char”需要收缩转换
test1.cpp(14): error C2398: 元素“5”: 从“double”转换到“int”需要收缩转换
test1.cpp(17): error C2397: 从“double”转换到“float”需要收缩转换
test1.cpp(19): error C2397: 从“unsigned __int64”转换到“float”需要收缩转换
test1.cpp(25): error C2397: 从“const int”转换到“char”需要收缩转换
*/
2. explicit关键字
(1)explicit用于阻止编译器的隐式转换,一般用于修饰构造函数。
(2)C++98/03由于不能使用{}列表初始化,即隐式转换只发生在调用带一个参数的构造函数中。但C++11允许用{}列表初始化对象,这可能会隐式调用带多个参数的构造函数。
(3)C++11中,explicit可用于修饰带多个参数的构造函数以防止隐式转换。(注意C++98/03中explicit被用于修饰只带一个参数的构造函数,如果修饰带多个参数的构造函数则无效)
【编程实验】explicit修饰带多参的构造函数
#include <iostream>
using namespace std; class Test
{
public:
Test(int a, int b)
{
cout <<"Test(int a, int b)" << endl;
} Test(initializer_list<int>)
{
cout <<"Test(initializer_list<int>)" << endl;
} explicit Test(int a, int b, int c)
{
cout <<"explicit Test(int a, int b, int c)" << endl;
}
}; void func(const Test& t)
{ } struct Complex
{
int real, imag; //explicit
Complex(int re, int im = ):real(re), imag(im){} Complex operator+(const Complex& x)
{
return Complex((real+x.real),(imag+x.imag));
}
}; int main()
{
Complex c1(, );
Complex c2 = c1 + ;//会试图将5转换为Complex类型,所以会隐式调用构造
//函数。为了阻止这种行为,可以在构造函数前加explicit //1.由于Test带有一个initializer_list参数的构造函数,因此,下列
//用{}初始化的对象都会直接调用该构造函数。
//2.如果注释掉上述构造函数,则编译器会将{...}分解并传给相应的
//构造函数,如果找不到相应的带多参的构造函数,则直接报错。
Test t1(, ); //Test(int a, int b)
Test t2{, }; //Test(initializer_list<int>)
Test t3{, , }; //Test(initializer_list<int>)
Test t4 = {, }; //Test(initializer_list<int>)
Test t5 = {, , };//Test(initializer_list<int>)
Test t6(, , ); //ok,显式调用explicit Test(int a, int b, int c) func({, }); //Test(initializer_list<int>)
func({, , }); //Test(initializer_list<int>)
func(Test{, }); //Test(initializer_list<int>)
func(Test{, , }); //Test(initializer_list<int>) Test t11{, , , }; //Test(initializer_list<int>)
Test t12 = {, , , };//Test(initializer_list<int>)
Test t13 {}; //Test(initializer_list<int>) return ;
}
/*测试结果:
**************************不注释Test中带有一个initializer_list参数的构造函数***************************
e:\Study\C++11\8>g++ -std=c++11 test2.cpp
e:\Study\C++11\8>a.exe
Test(int a, int b)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>)
explicit Test(int a, int b, int c)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>)
Test(initializer_list<int>) **************************不注释Test中带有一个initializer_list参数的构造函数***************************
e:\Study\C++11\8>g++ -std=c++11 test2.cpp -fno-elide-constructors
test2.cpp: In function 'int main()':
test2.cpp:55:22: error: converting to 'Test' from initializer list would use explicit constructor 'Test::Test(int, int, int)'
Test t5 = {77, 5, 42}; test2.cpp:59:18: error: converting to 'const Test' from initializer list would use explicit constructor 'Test::Test(int, int, int)'
func({47, 11, 3}); test2.cpp:63:25: error: no matching function for call to 'Test::Test(<brace-enclosed initializer list>)'
Test t11{77, 5, 42, 500}; test2.cpp:64:28: error: could not convert '{77, 5, 42, 500}' from '<brace-enclosed initializer list>' to 'Test'
Test t12 = {77, 5, 42, 500}; test2.cpp:65:14: error: no matching function for call to 'Test::Test(<brace-enclosed initializer list>)'
Test t13 {10};
*/
第8课 列表初始化(3)_防止类型收窄、explicit关键字的更多相关文章
- 第7课 列表初始化(2)_分析initializer_list<T>的实现
1. 初始化列表的实现 (1)当编译器看到{t1,t2…tn}时便会生成一个initializer_list<T>对象(其中的T为元素的类型),它关联到一个array<T,n> ...
- C++11 列表初始化
在我们实际编程中,我们经常会碰到变量初始化的问题,对于不同的变量初始化的手段多种多样,比如说对于一个数组我们可以使用 int arr[] = {1,2,3}的方式初始化,又比如对于一个简单的结构体: ...
- c++11——列表初始化
1. 使用列表初始化 在c++98/03中,对象的初始化方法有很多种,例如 int ar[3] = {1,2,3}; int arr[] = {1,2,3}; //普通数组 struct A{ int ...
- 列表初始化 分析initializer_list<T>的实现
列表初始化(1)_统一初始化 1. 统一初始化(Uniform Initialization) (1)在C++11之前,很多程序员特别是初学者对如何初始化一个变量或对象的问题很容易出现困惑.因为可以用 ...
- C++ Union妙用(将列表初始化用于数组元素)
Union是个不被注意的关键字,意为联合体,这是个诡异的名字.若不是为了继承C语言,它也不会出现在C++中(虽说,union在C++中得到了扩充,完成了接近类的功能).它的作用主要是节省内存空间,在嵌 ...
- initializer_list 列表初始化
initializer_list 列表初始化 用花括号初始化器列表初始化一个对象,其中对应构造函数接受一个 std::initializer_list 参数. #include <iostrea ...
- 默认初始化&拷贝初始化&直接初始化&值初始化&列表初始化
一.各种初始化的形式 /* 定义变量形式一:不指定初始值 */ int a; // 默认初始化 /* 定义变量形式二:指定初始值 */ int b = 1; // 拷贝初始化 int b(1); // ...
- C++结构体成员列表初始化
C++关于struct和class的区别,可以看上一篇文章:c ++ class和struct[转] 结构体成员列表初始化,来个例子: #include <iostream> #inclu ...
- C++新标准:列表初始化
一.列表初始化意义 C++新标准为vector提供了一种新的初始化方式:列表初始化.适用于知道多个成员具体值的情况. 二.列表初始化用法 /*1.空vector<int>*/ vector ...
随机推荐
- Singer 学习十三 发现模式
发现模式 发现模式提供了一种描述tap 支持数据流的方式,使用了json schema 做为描述数据的结构以及每个数据流的 类型,发现模式的实现依赖tap 的数据源,有些taps 将硬编码每个流的模式 ...
- DevExpress Cpicturebox或者Dev控件 PictureEdit 按比例的缩放加载图片
方法一: 如果要加载的图片的长宽比不是太过失衡, 1.可以改变picturebox的SizeMode属性为 PictureBoxSizeMode.StretchImage, 2.或者Dev控件 ...
- IBM WebSphere MQ介绍安装以及配置服务详解
首先介绍一下MQ MQ消息队列的简称是一种应用程序对应用程序的通信方法.说白了也就是通过队列的方式来对应用程序进行数据通信.而无需专用链接来链接它们. MQ的通讯方式 1.数据报的方式 Datagra ...
- Git中清除远程仓库HTTPS认证信息的方法
Git远程仓库同步时用户认证有两种方式:HTTPS.SSH,对应的Git仓库上有两个不同的链接地址. https方式使用账号和密码授权,简单易用,便于进行权限细分管理,而且防火墙一般会打开 http ...
- cos migration工具webhook推送
上一篇讲了腾讯云同步工具的使用,这篇主要是补充如何将同步结果主动消息通知. 因为cos migration 工具是java语言,并在github开源的,所以可以直接修改源码,添加webhook推送代码 ...
- ML(7)——支持向量机1(构建支持向量机)
支持向量机缩写是SVM(support vaector machine),这里的“机(machine)”是一个算法.在机器学习领域,常把一些算法看做是一个机器,如感知机(也叫感知器).支持向量机本身是 ...
- [转]浅谈UML的概念和模型之UML九种图
目录: UML的视图 UML的九种图 UML中类间的关系 上文我们介绍了,UML的视图,在每一种视图中都包含一个或多种图.本文我们重点讲解UML每种图的细节问题: 1.用例图(use case dia ...
- java 多线程详解
一.重点 重点: 1.创建和启动线程 2.实现线程调度 3.实现线程同步 4.实现线程通信 1.为什么要学习多线程? 当多个人访问电脑上同一资源的时候,要用到多线程,让每个人感觉很多电脑同时为多个人服 ...
- IDEA中使用springBoot+gradle构建多模块项目
https://blog.csdn.net/forMelo/article/details/78995875
- SDI工程时钟路径分析
SDI工程时钟路径分析 //------------- Receive Ports - RX Fabric Output Control Ports ------------- output rxou ...