#include <iostream>
using namespace std;
#include<vector>
//关于 C++ 中的变量,数组,对象等都有不同的初始化方法,在这些繁琐的初始化方法中没有任何一种方式适用于所有的情况。为了统一初始化方式,并且让初始化行为具有确定的效果,在 C++11 中提出了列表初始化的概念。
//在 C++98/03 中,对应普通数组和可以直接进行内存拷贝(memcpy ())的对象是可以使用列表初始化来初始化数据的
class Test
{ public:
Test(int ){};
private:
Test(const Test &){};
};
void func()
{
Test t1(520);
//Test t2 = 520; //这个会err 因为编译器会将520转换为Test对象再赋值给t2,而赋值的构造是私有函数
Test t3 = { 520 };
Test t4{ 520 }; //t3和t4是 c++11提供的统一初始化方法。
int a1 = { 1314 };
int a2{ 1314 };
int arr1[] = { 1, 2, 3 };
int arr2[]{ 1, 2, 3 };
}
//t2:语法错误,因为提供的拷贝构造函数是私有的。如果拷贝构造函数是公共的,520 会通过隐式类型转换被 Test(int) 构造成一个匿名对象,然后再通过对这个匿名对象进行拷贝构造得到 t2(这个错误在 VS 中不会出现,在 Linux 中使用 g++ 编译会提示描述的这个错误,截图如下。)
//列表初始化同样可以用于new创建出来的新对象。
void test2()
{
int *p=new int{520};
double b=double{13.14};
int * array= new int[3]{1,2,3};
}
//除此之外,列表初始化还可以直接用在函数返回值上:
class Person
{
public:
Person(int id, string name)
{
cout<<"id:"<<id<<",name:"<<name<<endl;
}
};
Person func2()
{
return{9527,"华安"}; //直接返回了一个匿名对象。
}
void test3()
{
Person p=func2();
}
//2列表初始化细节
//2.1聚合体
//在C++11中,列表初始化的使用范围被大大增强了,但是一些模糊的概念也随之而来,
//对于一个自定义类型,列表初始化可能有两种执行结果:
struct T1
{
int x;
int y;
}a={123,321};
struct T2{
int x;
int y;
T2(int,int):x(10),y(20){}
}b={123,321};
void test4()
{
cout<<"a.x"<<a.x<<",a.y:"<<a.y<<endl; //123 321
cout<<"b.x"<<b.x<<",b.y:"<<b.y<<endl; //10 20
}
//对象b并没有被初始化列表中的数据初始化,这是因为如果使用列表初始化对对象初始化时,
//还需要判断这个对象对应的类型是不是一个聚合体,如果是初始化列表中的数据就会被拷贝到对象中。
//普通数组本身可以看作是一个聚合类型
//满足一下条件的类(class,struct,union)可以被看作是一个聚合类型:
//无用户自定义的构造函数
//无私有或保护的非静态数据成员。
//场景1: 类中有私有成员,无法使用列表初始化进行初始化
struct T3
{
int x;
long y;
protected:
int z;
};//t{1,100,2}; //err,类中有私有成员,无法使用初始化列表初始化。
//场景2: 类中有非静态成员可以通过通过列表初始化进行初始化,但它不能初始化静态成员变量。
struct T4
{
int x;
long y;
protected:
static int z;
}t{1,100}; //ok
int T4::z=2;
//无基类,无虚函数。
//类中不能有使用{}和=直接初始化的非静态数据成员(从c++14开始就支持了).
struct T5
{
int x;
double y=1.14;
int z[3]{1,2,3};
}t2{520,13.14,{6,7,8}}; //err,c++11不支持,从c++14开始就支持了
//对于聚合类型的类可以直接使用列表初始化进行对象的初始化,如果不满足聚合条件还想使用列表初始化其实也是可以的,
//需要在类的内部自定义一个构造函数,在构造函数中使用初始化列表对类成员变量进行初始化:
//3 std::initializer_list
// 在 C++ 的 STL 容器中,可以进行任意长度的数据的初始化,使用初始化列表也只能进行固定参数的初始化,如果想要做到和 STL 一样有任意长度初始化的能力,可以使用 std::initializer_list 这个轻量级的类模板来实现。
// 先来介绍一下这个类模板的一些特点:
// 它是一个轻量级的容器类型,内部定义了迭代器 iterator 等容器必须的概念,遍历时得到的迭代器是只读的。
// 对于 std::initializer_list<T> 而言,它可以接收任意长度的初始化列表,但是要求元素必须是同种类型 T
// 在 std::initializer_list 内部有三个成员接口:size(), begin(), end()。
// std::initializer_list 对象只能被整体初始化或者赋值。
//3.1作为普通函数参数
//如果想要定义一个函数并且接受任意个数的参数(变参函数),只需要将函数参数指定为
//std::initializer_list, 使用初始化列表{}作为实参进行数据传递即可。
void traversal(std::initializer_list<int>a)
{
for(auto it=a.begin();it!=a.end();++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
void test5()
{
initializer_list<int> list;
cout << "current list size: " << list.size() << endl;
traversal(list);
list = { 1,2,3,4,5,6,7,8,9,0 };
cout << "current list size: " << list.size() << endl;
traversal(list);
cout << endl;
list = { 1,3,5,7,9 };
cout << "current list size: " << list.size() << endl;
traversal(list);
cout << endl;
////////////////////////////////////////////////////
////////////// 直接通过初始化列表传递数据 //////////////
////////////////////////////////////////////////////
traversal({ 2, 4, 6, 8, 0 });
cout << endl;
traversal({ 11,12,13,14,15,16 });
cout << endl;
}
//3.2作为构造函数参数
//自定义的类如果在构造对象的时候想要接收任意个数的实参,可以给构造函数指定为std::initializer_list
//类型,可以在自定义类的内部还是使用容器来存储接收的多个实参。
class Test2
{
public:
Test2(std::initializer_list<string> list)
{
for(auto it=list.begin();it!=list.end();++it)
{
cout<<*it<<" ";
m_names.push_back(*it);
}
cout<<endl;
}
private:
vector<string> m_names;
};
void test6()
{
Test2 t({ "jack", "lucy", "tom" });
Test2 t1({ "hello", "world", "nihao", "shijie" });
}
int main() {
test3();
test4();
test5();
test6();
//JSRUN引擎2.0,支持多达30种语言在线运行,全仿真在线交互输入输出。
cout << "Hello JSRUN! \n\n - from C++ ." << endl;
return 0;
}