C++面向对象-4-拷贝构造函数的调用时机

继续来学习构造函数,前面一篇学习了拷贝构造函数,至少了解了什么是拷贝构造函数,这篇就来学习下拷贝构造的使用。什么时候会使用到拷贝构造函数呢?大概可以分成三种场景:

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

 

使用一个已经创建完毕的对象来初始化一个新对象

这个很好理解,主要是前面已经花了经历去构造一个对象,如果我们再来一个这样的对象,我们很容易想到克隆,当前我们没有提供克隆方法,就可以通过拷贝构造来初始化一个新对象。

还是基于前面的代码,这里我们把属性权限改成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的地址是不是一样的

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值