【C++】5-1.10 深浅拷贝

【C++】5-1.10 深浅拷贝

  • 1、深浅拷贝
  • 2、浅拷贝示例
  • 3、深拷贝示例

1、深浅拷贝

在创建class类成员的时候:
如果class类的数据域是一个指针,就会遇到深浅拷贝的问题;

1.1、浅拷贝
浅拷贝:前提是class类的数据域是一个指针,只拷贝指针的地址,而非指针指向的内容;
出现的情况:
1.1.1、创建新对象时,调用类的隐式或者默认构造函数时;
1.1.2、使用默认赋值运算符,为已有对象赋值时;

1.2、深拷贝
深拷贝:重新在开辟一块空间(堆上),拷贝指针指向的内容!
(注意:class类的数据域是不是一个指针,那就不存在深浅拷贝这个概念了。)
出现的情况:
1.2.1、重载赋值运算符;
1.2.2、程序员自定义拷贝构造函数,拷贝指针指向的内容;

2、浅拷贝示例

以下代码参考博客:
【C++】5-1.7 析构函数
https://blog.csdn.net/jn10010537/article/details/116949278

date.h 头文件,内容如下:

#pragma once
#include 
#include
class date
{
     
private:
	int year{
      2021 };
	int month{
      5 };
	int day{
      22 };
public:
	date() = default;//强制编译器生成默认构造函数(无参构造函数)
	date(int y, int m, int d);//有参构造函数;

	// 声明get函数;
	int getYear();
	int getMonth();
	int getDay();
	std::string getString();

	// 声明set函数
	void setYear(int y);
	void setMonth(int m);
	void setDay(int d);
};

date.cpp 源文件,内容如下:

#include"date.h"
// 将声明与实现分离

// get 函数
int date::getYear() {
      return year; }
int date::getMonth() {
      return month; }
int date::getDay() {
      return day; }

//将日期转化成字符串形式,以便更好的显示
std::string date::getString()
{
     
	using namespace std;
	// 返回如 2021--05--22
	return to_string(year) + "--" + to_string(month) + "--" + to_string(day);
}

// set函数;
void date::setYear(int y) {
      year = y; }
void date::setMonth(int m) {
      month =m; }
void date::setDay(int d) {
      day = d; }

// 构造函数
date::date(int y, int m, int d) :year{
      y }, month{
      m }, day{
      d }
{
     
	std::cout << "[1]时间:" << getString() << std::endl;
}

staff.h 头文件,内容如下:

#pragma once
#include
#include
#include"date.h"

// 性别的枚举
enum class gender
{
     
	man,
	woman,
};

//定义一个员工的class
class staff
{
     
private:
	std::string staff_name;//员工姓名;
	gender staff_gender;   //员工性别;
	date*  staff_birthday; //员工的生日;对象指针,是一个指针,就可能存在深浅拷贝的情况
	static int staff_number; //员工数量;静态成员,不是类的数据成员!
public:
	// get 函数
	std::string getName();
	gender getGender();
	date getBirthday();
	std::string getString();

	// set函数;
	void setName(std::string set_name);
	void setGender(gender set_gender);
	void setBirthday(date set_birthday);

	//无参构造函数
	staff();	

	// 有参构造函数
	staff(std::string set_name, gender set_gender, date set_birthday);
	
	//析构函数
	~staff();
};

staff.cpp 源文件,内容如下:

#include"staff.h"
// 将声明与实现分离

// class类里面,声明静态成员之后
//一定不要忘记在class类外进行定义
int staff::staff_number = 0;

// get 函数
std::string staff::getName() {
      return staff_name;}
gender staff::getGender() {
      return staff_gender;}
date staff::getBirthday() {
      return *staff_birthday; }//指针解引用;

//转化成字符串形式,以便更好的显示
// 枚举数据的类型转化成字符串
std::string staff::getString()
{
     
	using namespace std;
	//gender::man 即带有作用范围限制的枚举类型,使用方式
	string enum_gender = (staff_gender == gender::man ? "man" : "woman");
	// staff_birthday 是date对象指针类型,有getString函数转化成字符串;
	string str_birthday = staff_birthday->getString(); //不是对象,而是指针,不能用点运算符号,用->运算符号;
	return staff_name + "--" + enum_gender + "--" + str_birthday;
}

// set函数;
void staff::setName(std::string set_name) {
      staff_name = set_name; }
void staff::setGender(gender set_gender) {
      staff_gender = set_gender;}
void staff::setBirthday(date set_birthday) {
     *staff_birthday = set_birthday;}

//无参构造函数
staff::staff()
{
     
	staff_number++;	
	std::cout << "[1]现在还有:"	<< staff_number	<< "员工。" << std::endl;
}

// 有参构造函数
// 由于 staff_birthday数据成员是对象指针,为避免浅拷贝:
// 程序员显示的自定义拷贝构造函数,深拷贝指针指向的内容;
staff::staff(std::string set_name, gender set_gender, date set_birthday) 
	:staff_name{
      set_name }, staff_gender{
      set_gender }// 构造函数初始化	
{
     
	staff_number++;
	
	// 在堆上开辟一块内存,并把内存地址赋值给staff_birthday;
	staff_birthday = new date{
      set_birthday };
	std::cout << "[2]现在还有:"<< staff_number<< "员工." << std::endl;
}

//析构函数
staff::~staff()
{
     
	staff_number--;
	std::cout << "[4]现在还有:"<< staff_number<< "员工。" << std::endl;
}

Shallow_copy.cpp 源文件,内容如下:

#include
#include"date.h"
#include"staff.h"

int main()
{
     
	// 编译器在栈上创建对象staff_1
	staff staff_1{
      "staff_1",gender::man,{
     2021,5,1} };//调用有参构造函数
	std::cout << "[5]" << staff_1.getString() << std::endl;
	std::cout << "******************" << std::endl;

	//编译器自动生成的隐式拷贝构造函数的方式创建对象staff_2
	staff staff_2{
      staff_1 };
	std::cout << "[6]" << staff_2.getString() << std::endl;
	std::cout << "###################" << std::endl;

	//std::cin.get();
	return 0;
}

debug x64 调试模式运行Shallow_copy.cpp 源文件,采用逐语句,查看:
staff_1、staff_2的staff_birthday成员地址如下:
【C++】5-1.10 深浅拷贝_第1张图片
运行如下:
【C++】5-1.10 深浅拷贝_第2张图片
即浅拷贝只拷贝了指针地址,没有重新申请内存来拷贝内容;

3、深拷贝示例

程序员显示添加拷贝构造函数,实现深拷贝;
每个对象的指针成员,都保存在不同的内存地址;

date.h 头文件,内容如下:

#pragma once
#include 
#include
class date
{
     
private:
	int year{
      2021 };
	int month{
      5 };
	int day{
      22 };
public:
	date() = default;//强制编译器生成默认构造函数(无参构造函数)
	date(int y, int m, int d);//有参构造函数;

	// 声明get函数;
	int getYear();
	int getMonth();
	int getDay();
	std::string getString();

	// 声明set函数
	void setYear(int y);
	void setMonth(int m);
	void setDay(int d);
};

date.cpp 源文件,内容如下:

#include"date.h"
// 将声明与实现分离

// get 函数
int date::getYear() {
      return year; }
int date::getMonth() {
      return month; }
int date::getDay() {
      return day; }

//将日期转化成字符串形式,以便更好的显示
std::string date::getString()
{
     
	using namespace std;
	// 返回如 2021--05--22
	return to_string(year) + "--" + to_string(month) + "--" + to_string(day);
}

// set函数;
void date::setYear(int y) {
      year = y; }
void date::setMonth(int m) {
      month =m; }
void date::setDay(int d) {
      day = d; }

// 构造函数
date::date(int y, int m, int d) :year{
      y }, month{
      m }, day{
      d }
{
     
	std::cout << "[1]时间:" << getString() << std::endl;
}

staff.h 头文件,内容如下:

#pragma once
#include
#include
#include"date.h"

// 性别的枚举
enum class gender
{
     
	man,
	woman,
};

//定义一个员工的class
class staff
{
     
private:
	std::string staff_name;//员工姓名;
	gender staff_gender;   //员工性别;
	date*  staff_birthday; //员工的生日;对象指针,是一个指针,就可能存在深浅拷贝的情况
	static int staff_number; //员工数量;静态成员,不是类的数据成员!
public:
	// get 函数
	std::string getName();
	gender getGender();
	date getBirthday();
	std::string getString();

	// set函数;
	void setName(std::string set_name);
	void setGender(gender set_gender);
	void setBirthday(date set_birthday);

	//无参构造函数
	staff();	

	// 有参构造函数
	staff(std::string set_name, gender set_gender, date set_birthday);

	//显示声明拷贝构造函数
	staff(const staff&);
	
	//析构函数
	~staff();
};

staff.cpp 源文件,内容如下:

#include"staff.h"
// 将声明与实现分离

// class类里面,声明静态成员之后
//一定不要忘记在class类外进行定义
int staff::staff_number = 0;

// get 函数
std::string staff::getName() {
      return staff_name;}
gender staff::getGender() {
      return staff_gender;}
date staff::getBirthday() {
      return *staff_birthday; }//指针解引用;

//转化成字符串形式,以便更好的显示
// 枚举数据的类型转化成字符串
std::string staff::getString()
{
     
	using namespace std;
	//gender::man 即带有作用范围限制的枚举类型,使用方式
	string enum_gender = (staff_gender == gender::man ? "man" : "woman");
	// staff_birthday 是date对象指针类型,有getString函数转化成字符串;
	string str_birthday = staff_birthday->getString(); //不是对象,而是指针,不能用点运算符号,用->运算符号;
	return staff_name + "--" + enum_gender + "--" + str_birthday;
}

// set函数;
void staff::setName(std::string set_name) {
      staff_name = set_name; }
void staff::setGender(gender set_gender) {
      staff_gender = set_gender;}
void staff::setBirthday(date set_birthday) {
     *staff_birthday = set_birthday;}

//无参构造函数
staff::staff()
{
     
	staff_number++;	
	std::cout << "[1]现在还有:"	<< staff_number	<< "员工。" << std::endl;
}

// 有参构造函数
// 由于 staff_birthday数据成员是对象指针,为避免浅拷贝:
// 程序员显示的自定义拷贝构造函数,深拷贝指针指向的内容;
staff::staff(std::string set_name, gender set_gender, date set_birthday) 
	:staff_name{
      set_name }, staff_gender{
      set_gender }// 构造函数初始化
	
{
     
	staff_number++;
	
	// 在堆上开辟一块内存,并把内存地址赋值给staff_birthday;
	staff_birthday = new date{
      set_birthday };
	std::cout << "[2]现在还有:"<< staff_number<< "员工." << std::endl;
}


//程序员显示声明拷贝构造函数,构造新的对象;
//在堆上开辟一块内存,并把内存地址赋值给staff_birthday;
staff::staff(const staff& person)
{
     
	staff_number++;
	staff_birthday = new date{
      *(person.staff_birthday) };	// 深拷贝生日
	
	staff_name = person.staff_name;	                       // 拷贝名字
	staff_gender = person.staff_gender;                    // 拷贝性别
	std::cout << "[3]现在还有:" << staff_number << "员工." << std::endl;
}

//析构函数
staff::~staff()
{
     
	staff_number--;
	std::cout << "[4]现在还有:"<< staff_number<< "员工。" << std::endl;
}

Deep_Copy.cpp 源文件,内容如下:

#include
#include"date.h"
#include"staff.h"

int main()
{
     
	// 编译器在栈上创建对象staff_1
	staff staff_1{
      "staff_1",gender::man,{
     2021,5,1} };//调用有参构造函数
	std::cout << "[5]" << staff_1.getString() << std::endl;
	std::cout << "******************" << std::endl;

	//编译器自动生成的隐式拷贝构造函数的方式创建对象staff_2
	staff staff_2{
      staff_1 };
	std::cout << "[6]" << staff_2.getString() << std::endl;
	std::cout << "###################" << std::endl;

	//std::cin.get();
	return 0;
}

debug x64 调试模式运行Deep_Copy.cpp 源文件,采用逐语句,查看:
staff_1、staff_2的staff_birthday成员地址如下:
【C++】5-1.10 深浅拷贝_第3张图片

你可能感兴趣的:(C++)