@CrazyHenry
2018-02-22T13:40:04.000000Z
字数 4482
阅读 1313
ccccC++Primer
- Author:李英民 | Henry
- E-mail: li
_
yingmin@
outlookdot
com- Home: https://liyingmin.wixsite.com/henry
快速了解我: About Me
转载请保留上述引用内容,谢谢配合!
class Fuck
{
public:
int a{};//使用1个初始化器,值初始化为0
int b{};
int c = {6};//等价于c{6},但是不推荐
Fuck():a{5}{}//使用1个初始化器,a被值初始化为5,实际这里用()更好,a(5)
};
int main()
{
Fuck bitch;
cout<<bitch.a<<" "<<bitch.b<<" "<<bitch.c<<endl;
unique_ptr<int[]> up(new int[10]{0,5,int(),int(8)});//0,5,0,8
//用int{8}也可,建议用int(8)
unique_ptr<string[]> up2(new string[10]{"5",string(8,'8'),"Hello"});//10个初始化器,其余被值初始化为空串
cout<<up2[1]<<endl;
vector<string> vs(9,"Hi");
return 0;
}
一个初始化器用于创建一个符合=左侧对象类型的对象。初始化器可以完成隐式类型转换("Hello"
转换为string("Hello")
),值初始化构造函数调用(当没有显示构造,就调用值初始化构造函数),显式构造函数调用如 string(9,'c')
!
使用{}
就是使用了初始化器。
需要调用单个对象的构造函数的时候,用()
,比如:
unique_ptr<string[]> up2(new string[10]{"5",string(8,'8'),"Hello"});//10个初始化器,其余被值初始化为空串
//string(8,'8')调用构造函数,不能用string{8,'8'}替代
//string s = {'H','i'};是使用类似vector的初始值列表所以,也可以用{}构造一个string对象
//new string[10]{"5",string(8,'8'),"Hello"});改为new string[10]{"5",{'8','8','8'...},"Hello"});也等价
//但是new string[10]{"5",{8,'8'},"Hello"});的意义就不一样了,编译器会把int型数据8理解为一个字符,和字符'8'一起,用于初始化一个string对象,8对于什么字符呢?
shared_ptr<vector<int>> sp(new vector<int>());
//初始化为空的vector<int>
unique_ptr<string[]> up2(new string[10]{"5",string(),"Hello"});//10个初始化器,其余被值初始化为空串
unique_ptr<string[]> up2(new string[10]{"5",string("Hello"),"Hello"});
//虽然string{"Hello"}也可以,但是建议使用()
class Fuck
{
public:
int a{};//使用1个初始化器,值初始化为0
int b{};
int c = {6};//等价于c{6},但是不推荐
Fuck():a(5){} //给单个对象初始化的时候,建议还是使用()而不是{}。除了是类内初始值的时候!
};
类内初始值以及列表初始化时候,用{}
//类内初始值
class Fuck
{
public:
int a{};//使用1个初始化器,值初始化为0
int b{};
int c = {6};//不好,用int c{6}更大气
string s{8,'8'};//error,只能用string s{"88888888"}
};
vector<int> vi{1,2,3,4,5};
有时候迫不得已,也只能用{}
:
int a{};//值初始化为0,int a()会认为是函数声明
class A;
A a{};//等价于A a,但是用A a()就会认为是函数声明
A a;
vector<A> vA{A(),A(args)};//用A()显得比A{}好
赋值是一定有=
号的:()
和{}
只是用于初始化:
int c = {6};
//为什么说这句代码显得不大气,就是将赋值和初始化没有搞清楚
//{}构造了一个初始化器,将字面值6转换为int对象6,然后赋值给c
//显得很多余
int c(6);//int型对象c初始化为6
int ds{};//只能这样初始化
ds{8};//error
ds(8);//error
ds = {8.8};//用8.8构造一个int对象8,赋值给ds
vector<int> vi{};//vi为空vector
//等价于vector<int> vi({});
//等价于vector<int> vi={};
vector<int> vi{1,2,3};//vi初始化为3个元素的vector
string s{'H','i'};//s初始化为2个元素的vector<char>
string s("Hello");//调用构造函数
string s{};//一个初始化器,调用默认构造函数构造一个空串,拷贝给s;与string s;等价
string as[10]{};//10个初始化器,调用10次默认构造函数,构造10个空串,拷贝给as
//可见,数组的空{}和vector<int>的空{}意义是不一样的,虽然都是“数组”,但是vector只构造一个初始化器用于vector对象自身。而数组构建10个初始化器,用于初始化每个元素。
//vector<int>的非空{}和数组的{}意义就是一样的了!都用于初始化元素。
//数组的{}只用于初始化元素
vector<int> vi({1,2,3,5,4});
//等价于vector<int> vi{1,2,3,5,4};
//等价于vector<int> vi={1,2,3,5,4};
unique_ptr<string[]> up2(new string[10]{"5",string{'8','8'},"Hello"});//10个初始化器,其余被值初始化为空串 。等价于string({'8','8'})
cout<<up2[1]<<endl;//输出88
vector<int> vi{};
//关于这句代码,总觉得有些别扭,主要在于{}里有值和无值时的动作似乎不一样。
//在我看来,vector<int>的构造函数一定是重载了initialization_list的,所以,上面的代码应该进入了这个构造函数。而不像普通的类,默认{}应该用于初始化器,初始化=左侧的对象,比如:
class Fuck
{
public:
int a{};//使用1个初始化器,值初始化为0
int b{};
int c = {6};//不好
Fuck():a{5},s(9,'c'){}//使用1个初始化器,a被值初始化为5
string s;
};
int main()
{
Fuck am{};
return 0;
}
//Fuck没有定义initialization_list的构造函数,但是Fuck am{}默认调用了默认构造函数!
//所以我认为,vector<int> vi{}和new vector<int>()应该是调用了不同的构造函数。但结果都是空vector。vector<int> vi{}调用了重载initialization_list的构造函数;vector<int>()调用默认构造函数。
//结论:{}对于容器,作用是构建每个元素的初始化器,而不是vector<T>对象本身。
//所以,一般直接使用
vector<int> vi;//调用默认构造函数,创建空vector
{}有两个功能,其一是初始值列表,其二就是匹配构造函数
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <typeinfo>
#include <numeric>
#include <memory>
#include <initializer_list>
using namespace std;
//win+<-/-> 切换窗口位置
//ctrl+win+<-/->切换桌面
//ctrl+alt+上/下 改变显示器方向
class Test
{
public:
Test(initializer_list<int> il):vi(il){cout<<"list cons"<<endl;}
vector<int> vi;
explicit Test(string s):vi{1,20} {cout<<"string cons"<<endl;}
};
int main()
{
Test ta{};
//这种空{}优先匹配默认构造函数,默认构造函数可以是explicit的,如果没有默认构造函数,则使用初始值列表构造函数
Test tf{1,2,3};//非空优先考虑初始值列表构造函数,如果无法初始化所有成员,则匹配某一构造函数
Test tb = {};
//拷贝初始化,右侧的{}会优先匹配默认构造函数,但是由于右侧会隐式转换,所以默认构造函数不能是explicit的
Test tb2 = {1,2,3};
//拷贝初始化,右侧的{}会优先匹配初始值列表构造函数,但是初始值列表构造函数不能是explicit的
Test tc({1,2,3});//等价于Test tf{1,2,3};并且初始值列表构造函数可以是explicit的
Test td{"Hello"};
//优先匹配初始值列表构造函数,如果成员无法转换为int,则匹配构造函数
//Test tg({"Hello"});//一定会调用初始值列表构造函数,如果成员无法转换为int,则报错
Test ti({});//一定会调用初始值列表构造函数
//Test te = {"Hello"};
//拷贝初始化,右侧用初始值列表构造函数构造临时量,如果"Hello"不能转换为int,将匹配构造函数(string s),而且(string s)构造函数不能是explicit的
return 0;
}
class Test
{
public:
Test(initializer_list<int> il):vi(il){cout<<"list cons"<<endl;}
vector<int> vi;
Test(string s):vi{1,20} {cout<<"string cons"<<endl;}
};
int main()
{
Test ta{};
Test tf{1,2,3};
Test tb = {};
Test tc({1,2,3});
Test td{"Hello"};
//Test tg({"Hello"});
Test te = {"Hello"};
return 0;
}