对学习C/C++感兴趣的可以看看这篇文章噢:C/C++目录
本文主要介绍C++中地初始化列表
目前对初始化列表应该有两个方面的定义,一个是类的构造函数中使用的那个初始化表,另一个则是C++11出现的std::initializer_list
下面来分别探讨这两个的初始化列表的具体细节与使用方式
首先是类中使用构造函数时的初始化表,其一般书写格式为:
class Test {
int x;
int y;
Test(int _x)
:x(_x),y(0)
{
}
};
即:在构造函数小括号与大括号之间,添加一个符号 :
,然后在其后依次写出要初始化的成员变量名称,其名称后面有一个()
,该小括号中的值就是将要赋值给成员变量的值
但实际上面这个效果与下面这段代码的效果是完全一样的:
Test(int _x)
{
x = _x;
y = 0;
}
但既然存在,那必然会有它的道理,不然也不可能会通过C++标准委员会的审核
所以下面我们再来看看这个例子:
class Test1 {
public:
Test1(){
cout << "Test1的默认构造函数" << endl;
}
Test1(const Test1& t) {
cout << "Test1的拷贝构造函数" << endl;
}
const Test1& operator=(const Test1& t) {
cout <<"Test1的赋值构造函数" << endl;
return *this;
}
};
class Test {
Test1 m_t1;
public:
Test(Test1 _t1)
//:t1(_t1)
{
m_t1 = _t1;
}
};
int main() {
Test1 t1;
Test t(t1);
}
代码略微有点长,但并不复杂:
Test1
类,并写好它的三个构造函数,用于测试调用这三个函数的情况Test
类,用于测试当将一个Test1
类作为成员变量,在给其赋值时发生的情况main
函数中,首先实例化一个Test1
类的对象t1
,然后传递给Test
类的构造函数中来实例化一个Test
对象首先是正常赋值情况下,其输出为:
Test1的默认构造函数
Test1的拷贝构造函数
Test1的默认构造函数
Test1的赋值构造函数
下面分析一下其输出的原因:
t1
对象时调用其默认构造函数输出t1
传入构造函数时,会将t1
拷贝给_t1
,所以调用了拷贝构造函数m_t1
,所以会调用其构造函数_t1
赋值给m_t1
,调用了赋值构造函数而如果将test
的构造函数改一下,采用初始化表:
Test(Test1 _t1)
:t1(_t1)
{
//t1 = _t1;
}
那么就会输出以下内容:
Test1的默认构造函数
Test1的拷贝构造函数
Test1的拷贝构造函数
前两行输出是和前面一样的,而第三行输出,则代替前面第三和第四行的输出
即:通过调用拷贝构造函数一次,来代替原本需要先默认构造,然后再赋值构造两大步骤
这就是有初始化列表这一特性的原因,通过减少构造,达到提高性能的作用
事实上,上面的代码还可以优化为:
Test(Test1& _t1)
:t1(_t1)
{
}
这样便去掉了第二行的输出,通过引用而减少了一次拷贝构造:
Test1的默认构造函数
Test1的拷贝构造函数
也就是说,对于类来说,一般我们使用初始化表会提高性能,而对于基本数据类型,其实没有什么提升
当初始化列表的好处也不仅仅于此,它的出现可以让我们初始化成员变量更加方便!
所以总的来说,能用初始化表就尽量用,基本没坏处。
紧接着便是C++11出现的initializer_list
,这同样是个好东西
首先我们还是来看看其主要用途
比如以往如果我们想要初始化一个vector
,那么就必须这样写:
vector<int> v;
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
这难免有点难看,但有了initializer_list
之后,我们就可以直接写为:
vector<int> v{1,1,1,1,1,1,1,1};
是不是方便多了!
注意我这里说的仅仅是方便,因为使用它并不会带来任何性能的提升,甚至会有些性能损失,它的出现就是为了方便我们程序员写代码的
其本质来说它就是一个模板,在标准库源文件中定义如下:
template <class _Elem>
class initializer_list
从这里可以看出来,它只有一个参数类型,所以你不能在一个初始化列表中放入不同的类型数据,比如:
vector<int> v{1 , 2.3 };
由于这里vector
已经指定了类型为int
,所以一旦使用小数就会报错
当然,其使用范围并不仅仅只是标准库,对于基本数据也是支持的:
int a{ 10 };
int b={ 10 };
上面两种写法都可以
如果我们想要给自己的类或函数添加一个初始化列表赋值怎么做呢?方法也很简单:
void test(initializer_list<int> ls) {
for (auto i = ls.begin(); i != ls.end(); i++) {
cout << *i << endl;
}
}
int main() {
test({1,2,3,4,5,5,6,7,8,9,10});
}
即:通过迭代器遍历即可