同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制(拷贝)是完全可行的。这个拷贝过程只需要拷贝数据成员,而函数成员是共用的(只有一份拷贝)。在建立对象时可用同一类的另一个对象来初始化该对象的存储空间,这时所用的构造函数称为拷贝构造函数。拷贝构造函数也是构造函数的一种,只是与构造函数的形参不同。
如果这里有一个空类型,编译器会自动加上6种函数(手动写了则不会提供)
文章图片
一个类里面值允许有一个缺省构造函数,否则程序就会报错,如:
文章图片
拷贝构造函数示例:
#include
#include
#include
using namespace std;
class Complex
{
int Real;
int Image;
public:
Complex() :Real(0), Image(0) {}//缺省的构造函数
Complex(int r,int i):Real(r),Image(i)//带参数的构造函数
{
cout << "Create Complex: " << this << endl;
}
~Complex()
{
cout << "Destroy Complex: " << this << endl;
} //不加引用&,则会变为无穷递归的形式,设置成值类型,必须要构建对象,而设计成引用,只是当前对象的别名
Complex(const Complex& cx) :Real(cx.Real), Image(cx.Image)//拷贝构造函数
{
cout << "Copy Create Complex: " << this << endl;
}
};
void func(Complex cx)
{
}
int main()
{
Complex c1;
func(c1);
Complex c2(c1);
//用c1初始化c2
Complex c3 = c1;
//Complex c3(c1)
Complex c4{ c1 };
return 0;
}
运行结果:
文章图片
练习1:写拷贝构造函数
文章图片
即将dt1的年份给dt2,dt1的月份给dt2,dt1的天数给dt2。
练习2:写拷贝构造函数
#include
#include
#include
using namespace std;
const int len = 20;
class CGoods
{
private:
char Name[len];
int Amount;
float Price;
float Total;
public:
CGoods(const char* name, int amount, float price)
:Amount(amount), Price(price)
{
strcpy_s(Name, len, name);
Total = amount * price;
}
CGoods(const CGoods& cx) :Amount(cx.Amount), Price(cx.Price),Total(cx.Total)
{
strcpy_s(Name, len, cx.Name);
}
};
int main()
{
CGoods c1("byd", 12, 560000.00);
CGoods c2(c1);
return 0;
}
运行结果:
文章图片
空指针和空字符串:
char* p=nullptr; //空指针拷贝构造函数还在另外两个方面使用: 当函数的形参是类的对象,调用函数时,进行形参与实参结合时使用。这时要在内存新建立一个局部对象,并把实参拷贝到新的对象空间中。
p=new char[100];
p[0]='\0'; //空字符串
三种不同函数的调用代表了三种不同的意图:
文章图片
深拷贝和浅拷贝: 浅拷贝:同一个字符串有两个指针指向,在运行主函数,调动析构函数时,会出现重复析构。
深拷贝:为了避免重复调用析构函数(重复释放空间),再给字符串申请一个空间,进行拷贝。
具体代码如下:
#include
#include
#include
using namespace std;
class Mystring
{
char* str;
public:
Mystring(const char* p = nullptr) :str(nullptr) //构造函数 获取堆区资源
{
if (p != nullptr)
{
int n = strlen(p) + 1;
//'\0'并不计算在字符串的长度,但是需要计算在空间中
str = new char[n];
strcpy_s(str, n, p);
}
else
{
str = new char[1];
*str = '\0';
} }
~Mystring()
{
delete[]str;
str = nullptr;
}
//Mystring(const Mystring& sx) :str(sx.str) {}// 浅拷贝 缺省拷贝构造函数,析构时,同一个空间会释放两次 Mystring(const Mystring& sx):str(nullptr)//深拷贝,不会重复析构空间
{
int n = strlen(sx.str) + 1;
str = new char[n];
strcpy_s(str, n, sx.str);
}
};
int main()
{ Mystring s1("yhpinghello");
Mystring s2(s1);
return 0;
}
运行结果:
文章图片
练习:代码如下
#include
#include
#include
enum { STACK_UNIT_SIZE = 10, STACK_INIT_SIZE = 2 };
using namespace std;
class MyStack
{
int* _data;
int _capc;
int _top;
public:
MyStack():_data(nullptr),_capc(STACK_INIT_SIZE),_top(-1)//构造函数
{
_data = https://www.it610.com/article/new(nothrow) int[_capc];
if (nullptr == _data)
exit(1);
}
~MyStack() //析构函数
{
delete[]_data;
_data = nullptr;
_capc = 0;
_top = -1;
}
};
void func(MyStack ms)
{
}
int main()
{
MyStack ita;
func(ita);
}
运行结果如下:
文章图片
程序会崩溃,在运行主函数时,编译器会自动调用浅拷贝函数,则会出现重复析构的情况。
运算符的重载: 下面先来看一段代码:
#include
#include
#include
using namespace std;
class Complex
{
private:
int Real;
int Image;
public:
Complex(int r = 0, int i = 0) :Real(r), Image(i) //缺省的构造函数
{
cout << "Create Complex: " << this << endl;
}
~Complex()
{
cout << "Destroy Complex: " << this << endl;
}
Complex(const Complex& cx) :Real(cx.Real), Image(cx.Image)
{
cout << "Copy Create Complex: " << this << endl;
}
voidPrint() const
{
cout << "Real: " << Real << "Image: " << Image << endl;
}
Complex Add(Complex cx)
{
int r = this->Real + cx.Real;
int i = this->Image + cx.Image;
Complex tmp(r, i);
return tmp;
}
};
int main()
{
Complex c1(1, 2), c2(3, 4), c3;
c3 = c1.Add(c2);
//c3=Add(&c1,c2)
c3.Print();
return 0;
}
运行结果如下:
文章图片
上面代码在程序运行时,一共创建了6个对象,即:c1, c2, c3, this指针,cx副本,tmp,则可以发现创建的个数过多,为了使创建的对象足够小,那么就需要修改Add函数。
文章图片
加法运算符重载:
文章图片
注:构造函数,析构函数和拷贝构造函数都不能具有常性(不能加const),
拷贝构造函数是按位拷贝。无论在什么函数(拷贝构造,析构函数,赋值重载......)中,
绝对禁止使用memmove或者memset函数
左值(lvalue):对该值能够取地址 &a,&dx
右值(rvalue): 字面常量称之为右值,如10,不能取地址符
将亡值(xvalue): 在程序中运行时,会产生一个临时变量,则将该临时量称之为将亡值。将亡值不是一个静态变量,只有在程序运行时,才会产生。当将亡值没有取名字时是一个右值(如上面程序中的tmp);有名字的将亡值为左值(如:Complex c4=Complex(5,6) )。
【笔记|C++:拷贝构造函数,深拷贝,浅拷贝以及运算符的重载】
推荐阅读
- python|Python模块和包的管理
- c++基础及其STL|c++基础篇——(一)c++快速入门(上)
- 笔记|卷积神经网络 —— 图像识别与深度学习
- 笔记|卷积神经网络 —— 深度学习三要素
- 笔记|花一天时间体验 wintogo 到最终放弃
- 笔记|Serial.println()里用和不用F()的区别
- java|基于SSM的Java图书管理系统
- java|Spring Boot在线教育系统
- Dubbo | Dubbo快速上手笔记 - 环境与配置 #yyds干货盘点#