在创建class类成员的时候:
如果class类的数据域是一个指针,就会遇到深浅拷贝的问题;
1.1、浅拷贝
浅拷贝:前提是class类的数据域是一个指针,只拷贝指针的地址,而非指针指向的内容;
出现的情况:
1.1.1、创建新对象时,调用类的隐式或者默认构造函数时;
1.1.2、使用默认赋值运算符,为已有对象赋值时;
1.2、深拷贝
深拷贝:重新在开辟一块空间(堆上),拷贝指针指向的内容!
(注意:class类的数据域是不是一个指针,那就不存在深浅拷贝这个概念了。)
出现的情况:
1.2.1、重载赋值运算符;
1.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成员地址如下:
运行如下:
即浅拷贝只拷贝了指针地址,没有重新申请内存来拷贝内容;
程序员显示添加拷贝构造函数,实现深拷贝;
每个对象的指针成员,都保存在不同的内存地址;
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成员地址如下: