在网上看到许多类似的博客内容,许多都是转发的,我不知道他们验证过没有,反正我试了之后发现,这根本不对,原内容如下:
我持着怀疑的态度去验证,发现即使用大括号来初始化,也不会调用默认构造函数,代码如下(没有任何输出):
class Animal
{
public:
Animal() { cout << "调用我了没?" << endl; }
/*Animal(int weight, int height) : //方法1
m_weight(weight),
m_height(height)
{
}*/
Animal(int weight, int height) //方法2
{
m_weight=weight;
m_height=weight;
}
private:
int m_weight;
int m_height;
};
int main()
{
Animal a(2,3);
}
然后我又用其它方法验证:对上述方法1和方法2,主函数改动如下:
int main()
{
clock_t _start, _stop;
_start = clock();
for (int i = 0; i < 10000000; i++)
{
Animal a(2,3);
}
_stop = clock();
cout << (double) ( _stop - _start ) / CLOCKS_PER_SEC << endl;
}
经过多次运行,两种方法的时间都大致为0.238秒左右,并没有较大波动,也就是说,使用方法2,并没有调用默认构造函数来浪费额外的时间。
那么,方法1,也就是初始化列表的作用是什么呢?据我的理解,有如下两点:
1、初始化父类
现在给父类加一个派生类Dog:
class Animal
{
public:
Animal() { cout << "调用我了没?" << endl; }
/*Animal(int weight, int height) : //方法1
m_weight(weight),
m_height(height)
{
}*/
Animal(int weight, int height) //方法2
{
m_weight=weight;
m_height=weight;
}
private:
int m_weight;
int m_height;
};
class Dog :public Animal
{
public:
Dog(int a, int b):da(a), db(b) { };
~Dog() {};
private:
int da, db;
};
此时如果,main函数里面像下面这么写肯定没问题:
int main()
{
Dog d(2,3);
}
但如果把方法1上面的那个无参构造函数(作用等于默认构造函数)给注释掉,那么就会报错,错误为无法找到父类的默认构造函数,那么怎么办,此时初始化列表的第一个作用就出来了, 可以给Dog类这么加:
class Dog :public Animal
{
public:
Dog(int a, int b) :Animal(a, b), da(a), db(b) { };
~Dog() {};
private:
int da, db;
};
注意,如果进入大括号,则意味着父类已经初始化完,因此只能这么干。
这里再啰嗦两句初始化顺序的问题,具体就不用代码展开来试验了,已经我都验证过:初始化列表的初始化顺序与变量定义的顺序一致或类继承顺序一致,如果变量初始化时用到了位于同一列表的其它刚刚被初始化的变量,那这点尤为要注意。
2、初始化列表的第二个作用:
这个简单说一下,就是可以用来初始化类中的const常量和初始化引用等,因为const的量和引用这种只能被初始化一次,后面就不能更改了,因此只能在初始化列表中解决。而且不在这里解决,编译都过不去。