【C++ | 拷贝构造函数】一文了解C++的 拷贝(复制)构造函数

wkd_007 2024-08-17 10:05:03 阅读 76

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀

🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭

⏰发布时间⏰:2024-06-07 21:05:34

本文未经允许,不得转发!!!

目录

🎄一、为什么需要 拷贝构造函数🎄二、什么是 拷贝构造函数🎄三、使用 拷贝构造函数🎄四、默认的 拷贝构造函数🎄五、总结


在这里插入图片描述

🎄一、为什么需要 拷贝构造函数

如果程序中出现需要 拷贝构造函数 的代码,而又没有提供拷贝构造函数时,系统会提供一个默认的拷贝构造函数,该函数只会完成浅拷贝而不会进行深拷贝,这就是为什么需要 拷贝构造函数 的原因。

关于浅拷贝、深拷贝的知识,可以看这篇文章:C++入门知识-拷贝构造函数-浅拷贝、深拷贝

下面用例子说明浅拷贝可能产生的问题:

<code>// g++ 11_Copy_Constructor_Date.cpp

#include <iostream>

#include <stdio.h>

using namespace std;

class CDate

{

public:

CDate(int year, int mon, int day);// 构造函数声明

~CDate();// 析构函数声明

void show()

{

//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;

cout << "Date: " << str << endl;

}

private:

int m_year;

int m_mon;

int m_day;

char *str;

};

// 构造函数定义

CDate::CDate(int year, int mon, int day)

{

m_year = year;

m_mon = mon;

m_day = day;

str = new char[64];

sprintf(str, "%4d.%02d.%02d", year,mon,day);

cout << "Calling Constructor" << ", this=" << this <<endl;

}

// 析构函数定义

CDate::~CDate()

{

cout << "Calling Destructor" << ", this=" << this <<endl;

delete [] str;

}

int main()

{

CDate date_1(2024,06,05);

CDate date_2 = date_1;// 调用拷贝构造函数

date_1.show();

date_2.show();

return 0;

}

上面代码由于没有进行深拷贝,导致 double free 了的错误,因为浅拷贝只复制了str的值,在两个对象销毁时都delete了。

在这里插入图片描述


在这里插入图片描述

🎄二、什么是 拷贝构造函数

<code>拷贝构造函数,有些书也把其成为复制构造函数,其作用是将一个对象复制到新创建的对象中。

类的拷贝构造函数原型通常是这样的:类名(const 类名 &);。以CDate类为例,其拷贝构造函数如下:

CDate(const CDate & date);

拷贝构造函数的几个特点:

1、函数名和类名相同,因为它也是构造函数的一种;

2、第一个参数必须是一个自身类类型的引用,且其他参数都有默认值。

3、第一个参数必须是自身类类型的引用的原因:如果不是引用则需要拷贝它的实参,为了要拷贝实参,又需要调用拷贝构造函数,如此无限循环;

清楚了这些之后,我们修改一下上个小节的代码,添加一个拷贝构造函数:

// g++ 11_Copy_Constructor_Date.cpp

#include <iostream>

#include <stdio.h>

using namespace std;

class CDate

{

public:

CDate(int year, int mon, int day);// 构造函数声明

CDate(const CDate& date);// 拷贝构造函数声明

~CDate();// 析构函数声明

void show()

{

//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;

cout << "Date: " << str << endl;

}

private:

int m_year;

int m_mon;

int m_day;

char *str;

};

// 构造函数定义

CDate::CDate(int year, int mon, int day)

{

m_year = year;

m_mon = mon;

m_day = day;

str = new char[64];

sprintf(str, "%4d.%02d.%02d", year,mon,day);

cout << "Calling Constructor" << ", this=" << this <<endl;

}

// 拷贝构造函数定义

CDate::CDate(const CDate& date)

{

m_year = date.m_year;

m_mon = date.m_mon;

m_day = date.m_day;

str = new char[64];

sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);code>

cout << "Calling Copy Constructor" << ", this=" << this <<endl;

}

// 析构函数定义

CDate::~CDate()

{

cout << "Calling Destructor" << ", this=" << this <<endl;

delete [] str;

}

int main()

{

CDate date_1(2024,06,05);

CDate date_2 = date_1;// 调用date_2的拷贝构造函数

date_1.show();

date_2.show();

return 0;

}

运行结果如下,添加拷贝构造函数后,运行不会报错,因为拷贝构造函数中重新new了内存:

在这里插入图片描述


在这里插入图片描述

🎄三、使用 拷贝构造函数

为了使用 拷贝构造函数,我们必须清楚 拷贝构造函数 在什么情况下会被调用,然后再根据自己设计的类是否需要深拷贝来决定怎样定义该类的 拷贝构造函数。

会调用拷贝构造函数的几种情况:

使用同类型的对象去初始化另一个对象时。

如下代码,使用了 date_1 初始化 date_2:

<code>CDate date_1(2024,06,05);

CDate date_2 = date_1;// 调用date_2的拷贝构造函数

将一个对象作为实参传递给一个非引用类型的形参。

void printDate(CDate date)

{

date.show();

}

...

printDate(date_2);// 实参传值到形参,调用拷贝构造函数

从一个返冋类型为非引用类型的函数返回一个对象。

CDate g_date(2024,06,06);;

CDate getDate()

{

return g_date;// 3、返回对象时,调用拷贝构造函数

}

下面例子演示了调用拷贝构造函数的这三种场景:

// g++ 11_Copy_Constructor_Date.cpp

#include <iostream>

#include <stdio.h>

using namespace std;

class CDate

{

public:

CDate(int year, int mon, int day);// 构造函数声明

CDate(const CDate& date);// 拷贝构造函数声明

~CDate();// 析构函数声明

void show()

{

//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;

cout << "Date: " << str << endl;

}

private:

int m_year;

int m_mon;

int m_day;

char *str;

};

// 构造函数定义

CDate::CDate(int year, int mon, int day)

{

m_year = year;

m_mon = mon;

m_day = day;

str = new char[64];

sprintf(str, "%4d.%02d.%02d", year,mon,day);

cout << "Calling Constructor" << ", this=" << this <<endl;

}

// 拷贝构造函数定义

CDate::CDate(const CDate& date)

{

m_year = date.m_year;

m_mon = date.m_mon;

m_day = date.m_day;

str = new char[64];

sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);code>

cout << "Calling Copy Constructor" << ", this=" << this <<endl;

}

// 析构函数定义

CDate::~CDate()

{

cout << "Calling Destructor" << ", this=" << this <<endl;

delete [] str;

}

void printDate(CDate date)

{

date.show();

}

CDate g_date(2024,06,06);;

CDate getDate()

{

return g_date;// 3、返回对象时,调用拷贝构造函数

}

int main()

{

CDate date_1(2024,06,05);

CDate date_2 = date_1;// 1、调用date_2的拷贝构造函数

date_1.show();

date_2.show();

cout << endl;

printDate(date_2);// 2、实参传值到形参,调用拷贝构造函数

cout << endl;

getDate();

cout << endl;

return 0;

}

运行结果:

在这里插入图片描述


在这里插入图片描述

🎄四、默认的 拷贝构造函数

如果没有为一个类定义拷贝构造函数,则编译器会合成一个“默认拷贝构造函数”。

默认的拷贝构造函数会逐个复制非静态成员( 成员复制也称为浅复制)的值到正在创建的对象中。根据成员类型有下面几种情况:

1、如果成员是内置类型,则直接复制;

2、如果成员本身就是类对象,则将使用这个类的拷贝构造函数来复制类对象;

3、如果成员是数组,默认的拷贝构造函数会逐元素地拷贝一个数组类型的成员。


在这里插入图片描述

🎄五、总结

👉本文介绍C++的拷贝构造函数,为什么需要拷贝构造函数,什么是拷贝构造函数,怎么使用拷贝构造函数,默认拷贝构造函数。

在这里插入图片描述

如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。