当一个对象被创建时,会发生什么情况呢?
例如:
template<typename T>
class boy{
public:
boy(const string &new_name, T *ptr){
name = newname;
adress = ptr;
}
......
private:
sting name;
T *adress;
}
对于上述这个类而言,当我们在某处执行 :
string *n_ptr = &n_adress;//一个之前被定义的string对象
boy<srting> *jerry = new boy("jerry", n_ptr);
此时会发生以下几件事:
1.编译器根据模板实例化一个boy<string>类,并生成相关的函数,这将在编译期完成。
2.对于new boy("jerry", n_ptr);编译器会根据字符串字面值生成一个临时对象,然后下面的语句将变成:
string _temp("jerry");//这里会调用string对象的构造函数。
boy<string> *jerry = new boy(_temp, n_ptr);
3.new 运算符会调用operator new标准库函数为对象分配空间,然后调用对象的构造函数。
4.在operator new 分配空间后,编译器还要保证完成一件事情,那就是为生成boy<string>对象而首先对该对象的各个数据成员
进行初始化。于是这里相对应boy<string>类有两个数据成员,一个时string类得对象,一个是T类(即string类)的指针。对string类
成员的初始化会调用string类得默认构造函数,于是,编译器在这里会生成调用string、类构造函数的代码插入到代码片段中。
5.执行boy<string>类得构造函数,即执行函数体,而在函数体中,又有两个赋值语句:
name = new_name;
adress = ptr;
从第一个赋值语句可以看出,这里又调用了以此string对象的operator =,于是,上面的那次默认构造函数的调用完全是多余的。
而当我们将类改写成:
template<typename T>
class boy{
public:
boy(const string &new_name, T *ptr):name(new_name),adress(ptr){
}
......
private:
sting name;
T *adress;
};
这时,我们所做的工作就简单的多,成员初始化列表完成的功能只有一件事:告诉编译器,我们将如此初始化我们的成员,
于是,当new操作符调用operator new 分配完对象的内存空间后,编译器会把string对象的拷贝构造函数安插到代码中,以完成
对象的初始化工作,而构造函数的函数体内,什么都不做,这样,我们编制调用了一次构造函数,这便是效率的体现。