复制构造函数
复制构造,用一个已有的对象来创建一个新对象,用已有对象的数据来对新对象的数据进行初始化。
A a1;
A a2(a1);
复制构造函数 就是在通过复制构造来创建新的对象的时候,会被自动调用的函数。
复制构造函数的调用场景
在哪些情况下会自动调用复制构造函数?
1 明确的指出用复制构造的方式来创建新的对象。
A a1;
A a2(a1);
A a3 = a1;
A a3;
a3 = a1;
C++支持对象的赋值。对象的赋值默认情况下完成的是完全复制。
2 当函数的形式参数是对象,进行函数调用的时候,会用实参来复制形参,也会调用复制构造函数(拷贝构造函数)。
void f( A a){
}
int main(){
A a1;
f(a1);
}
所以,当传递对象的时候,推荐使用引用作为函数的参数,减少系统开销。
3 当函数的返回值是对象的时候,会用该返回的对象通过复制构造的方式去创建一个临时对象。在Dev C++中实验显示没有调用,原因可能是编译器对代码进行了优化。
A g(){
A a;
return a;
}
int main(){
A a1;
a1 = g();
}
//4_2.cpp
#include
using namespace std;
class Point { //Point 类的定义
public: //外部接口
Point(int xx = 0, int yy = 0) { //构造函数
x = xx;
y = yy;
}
Point(Point &p); //拷贝构造函数
int getX() {
return x;
}
int getY() {
return y;
}
private: //私有数据
int x, y;
};
//成员函数的实现
Point::Point(Point &p) {
x = p.x;
y = p.y;
cout << “Calling the copy constructor” << endl;
}
//形参为Point类对象的函数
void fun1(Point p) {
cout << p.getX() << endl;
}
//返回值为Point类对象的函数
Point fun2() {
Point a(1, 2);
return a;
}
//主程序
int main() {
Point a(4, 5); //第一个对象A
Point b = a; //情况一,用A初始化B。第一次调用拷贝构造函数
cout << b.getX() << endl;
fun1(b); //情况二,对象B作为fun1的实参。第二次调用拷贝构造函数
b = fun2(); //情况三,函数的返回值是类对象,函数返回时,调用拷贝构造函数
cout << b.getX() << endl;
return 0;
}
构造函数和类型转换之间的关系(补充)
类型转换:将一种类型转换为其他类型。
有两类转换形式
显式转换
int i = 6;
double d;
d = double(i);
d = (double) i;
隐式类型转换
d = i;
在赋值、或者参数传递过程中,如果两者之间的类型是可以转换的,则自动进行类型转换。
Point(1,2); 直接创建一个临时对象。
p1 = Point(1);
从面向对象的角度看,是创建一个临时的对象。
从类型转换的角度看,将整形转换成了Point类型。
可以将右边的类的类型转换为左边的类的类型的条件
1 类型之间是兼容的 int double
2 如果左边的类的构造函数支持用右边的类型的一个变量作为参数进行调用。本质是要利用构造函数创建一个临时对象,从最终的效果来看,相当于类型转换。
有的时候,这个性质在发生隐式类型转换的时候会让代码不直观。p1 = 1;
explicit Point(int x1,int y1=0){
x = x1;
y = y1;
}
防止通过构造函数进行隐式类型转换,提高程序的可读性。
#include
using namespace std;
class Point{
public:
explicit Point(int x1,int y1=0){
x = x1;
y = y1;
}
private:
int x,y;
};
int main(){
Point p1(2,3);
//p1 = Point(1);
p1 = (Point)1;
//p1 = 1;
}
类的组合(*)
一个大的类里面会包含其他小的类的对象作为它的成员,模拟了用小的东西组成大的东西这样一个现实世界经常发生的现象。
组合类:指大的类(整体)。
内嵌对象:在组合类里面定义的其他类的对象。(局部,小的部件)
内嵌类:内嵌对象所对应的类。
在类组合的时候要解决的关键问题?
如何对内嵌对象的数据进行初始化?
有个特殊的规定:当创建组合类的对象的时候,会先调用内嵌对象的构造函数对内嵌对象进行初始化。
如何调用内嵌对象的构造函数呢?
通过初始化列表来完成,初始化列表中也可以对普通成员进行初始化
Line(int x1,int y1,int x2,int y2):p1(x1,y1),p2(x2,y2), len(0)
{
//p1.x = x1;
}
如果初始化列表中没有写创建对象的语句,则编译器自动调用内嵌对象的无参的构造函数来创建内嵌对象。
组合类的情况下构造函数的调用顺序:
先创建内嵌对象,再执行组合类构造函数里面的代码。
析构函数的调用顺序和构造函数相反。
如何写组合类的复制构造函数?
Line(Line & l):p1(l.p1),p2(l.p2){
}