继续来学习构造函数,前面一篇学习了拷贝构造函数,至少了解了什么是拷贝构造函数,这篇就来学习下拷贝构造的使用。什么时候会使用到拷贝构造函数呢?大概可以分成三种场景:
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
使用一个已经创建完毕的对象来初始化一个新对象
这个很好理解,主要是前面已经花了经历去构造一个对象,如果我们再来一个这样的对象,我们很容易想到克隆,当前我们没有提供克隆方法,就可以通过拷贝构造来初始化一个新对象。
还是基于前面的代码,这里我们把属性权限改成public,这里就不写set和get方法,方便这里少一点代码
#include<iostream>
using namespace std;
class Point
{
public:
//构造函数
Point()
{
cout << "调用了构造函数"<< endl;
}
//有参构造
Point(int x, int y)
{
cout << "调用了有参构造函数" << endl;
X = x;
Y = y;
}
//拷贝构造
Point(const Point &p)
{
cout << "调用了拷贝构造函数" << endl;
//将p的属性拷贝到当前类的初始化
X = p.X;
Y = p.Y;
}
//析构函数
~Point()
{
cout << "调用了析构函数" << endl;
}
public:
int X;
int Y;
};
void test01()
{
Point p1(10, 10);
Point p2(p1); // 拷贝构造
cout << "P2的X轴坐标是:" << p2.X << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果
上面打印了p2的X坐标是10,说明拷贝过来了,这种场景是我们使用拷贝构造函数的最多场景。
值传递的方式给函数参数传值
先看下面代码,再来解释,这个有一点点绕,但是只要记住一点就好理解。值传递是,先拷贝出一个值的副本,然后再传递给形参。对这句话理解很重要。
#include<iostream>
using namespace std;
class Point
{
public:
//构造函数
Point()
{
cout << "调用了构造函数"<< endl;
}
//有参构造
Point(int x, int y)
{
cout << "调用了有参构造函数" << endl;
X = x;
Y = y;
}
//拷贝构造
Point(const Point &p)
{
cout << "调用了拷贝构造函数" << endl;
//将p的属性拷贝到当前类的初始化
X = p.X;
Y = p.Y;
}
//析构函数
~Point()
{
cout << "调用了析构函数" << endl;
}
public:
int X;
int Y;
};
void doSomething(Point p)
{
// do something
}
void test01()
{
Point p1;
doSomething(p1);
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果:
借助上面红圈和箭头,我们来分析下这个代码的执行过程。
1)执行Point p1, 这个肯定调用了默认的无参构造函数,这个理解肯定没问题
2)开始执行doSothing(p1),p1是上一行代码定义的,这是一个实参,doSomething(People p)这个p是形参
3)doSothing(p1)中传入的p1(51行代码)是实参p1(50行代码)的一个副本,因为这里是值传递。
4)这是是副本,就是一个拷贝过程,编译器帮我们做了这个拷贝过程,所以执行了拷贝构造函数的调用
5)需要强调,假如doSomething函数中修改了X和Y的值,这个和50行代码中p1的X和Y的值没有任何影响,因为两个是完全不相同的两个对象。
以值方式返回局部对象
也是直接来看代码,然后进行分析
#include<iostream>
using namespace std;
class Point
{
public:
//构造函数
Point()
{
cout << "调用了构造函数"<< endl;
}
//有参构造
Point(int x, int y)
{
cout << "调用了有参构造函数" << endl;
X = x;
Y = y;
}
//拷贝构造
Point(const Point &p)
{
cout << "调用了拷贝构造函数" << endl;
//将p的属性拷贝到当前类的初始化
X = p.X;
Y = p.Y;
}
//析构函数
~Point()
{
cout << "调用了析构函数" << endl;
}
public:
int X;
int Y;
};
Point doSomething()
{
Point p1;
return p1;
}
void test01()
{
Point p = doSomething();
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果
分析:
主要看doSomething()函数,第一步,Point p1,调用的时候走的是默认无参构造函数。这个函数里面定义的Point p1是一个局部变量,函数执行完毕就会自动销毁。关键点就是在这里,return p1 这个p1和Point p1不是同一个对象,这里是以值返回,返回拿到的这个p1是45行代码这个p1的一个拷贝副本,所以这个时候调用了拷贝构造。
我们可以通过打印内存地址来看看p1和外面接收的p的地址是不是一样的