C++之构造函数
构造函数
- 默认构造函数:仅当没有定义任何构造函数的时候,编译器才会提供默认构造函数,为类定义了构造函数,程序员就必须为他提供默认构造函数。两种创建方式:1.给已有的构造函数所有参数提供默认值2.定义一个没有参数的构造函数。
- 初始化构造函数:利用成员初始化列表进行数据的初始化
- 拷贝构造函数:一个对象初始化另外一个对象的时候调用,返回值生成一个对象的时候。
- 移动构造函数:窃取临时对象的资源,区别于拷贝赋值函数。需要了解右值引用,move语义,完美转发。
- 转换构造函数:只接受一个参数的构造函数定义了从参数类型到类类型的转换,区别于转换函数(类类型到参数类型的转换)。
如下程序所示:
class Student{
public:
Student(){//通常默认构造函数要给所有成员提供初始值
this->age=1;//静态成员没有this指针
this->name=10;
};
Student(int a,int n):age(a),name(n){};//构造函数+成员列表初始化
Student(const Student&s);//拷贝构造函数
Student(const Student&&s);//移动构造函数
Student(int a,int n=1):age(a),name(1){}//转换构造函数+成员列表初始化
private:
int age;
int name;
}
成员初始化列表和构造函数体内赋值的区别
首先,当数据类型是普通内置类型的时候,两种方式都没有区别
但是,当数据成员是类对象的时候,两者就有比较大的区别。所以建议都使用成员列表初始化。通俗来说就是利用构造函数初始化是用一个已经构造的对象去生成另外一个对象,这另外一个对象是事先没有的,需要通过已有的对象去构造,而赋值是=两边都有对象,是两个对象都已经构造出来过了,然后进行一个对象向另一个对象的赋值。
从下面程序开始:
class A {
public:
A() {
cout << "默认构造函数A()" << endl;
}
A(const A&) {
cout << "拷贝构造函数" << endl;
}
A&operator=(const A&) {
cout << "拷贝赋值函数" << endl;
return *this;
}
};
class B {
public:
B(A data) {//构造函数体内赋值
m_data = data;
}
private:
A m_data;
//int value;
};
int main() {
A a;
B test(a);
return 0;
}
可以看出,当执行
A a;
第一次调用默认构造函数。
当执行
B test(a)//
首先,实参对象a传递给形参对象data,这会调用A的拷贝构造函数,然后B的构造函数要使用m_data,又会调用A的构造函数生成m_data,最后调用拷贝赋值函数将一个对象赋值给另一个对象。
当使用初始化列表的时候
class A {
public:
A() {
cout << "默认构造函数A()" << endl;
}
A(const A&) {
cout << "拷贝构造函数" << endl;
}
A&operator=(const A&) {
cout << "拷贝赋值函数" << endl;
return *this;
}
};
class B {
public:
//B(A data) {//构造函数体内赋值
// m_data = data;
//}
B(A data) :m_data(data) {};
//B(A& data) :m_data(data) {};
private:
A m_data;
//int value;
};
int main() {
A a;
B test(a);
return 0;
}
区别就在
B test(a);
首先,实参a传入形参data时候会调用拷贝构造函数,然后直接进行一个对象初始化另一个对象的操作,还是调用拷贝构造函数。当然,可以使用引用提高效率。
这样,其实就是a直接传入,不用在经过实参a传入形参data时候会调用拷贝构造函数这一步。
参考:C++成员初始化列表的高效性
书本:《c++primer plus》