首页 > 编程语言 >【C++】类和对象(3)(默认成员函数--拷贝构造&赋值重载)

【C++】类和对象(3)(默认成员函数--拷贝构造&赋值重载)

时间:2024-10-09 20:48:05浏览次数:14  
标签:const -- C++ Date int 重载 拷贝 day

引言

前文介绍了C++中默认成员函数中的构造函数和析构函数,相信已经对它们的功能与用法有了基本认识,本文接着介绍也很常见的拷贝构造函数和赋值重载函数,便于对C++进一步的学习。

拷贝构造函数

补充知识:深浅拷贝

深拷贝和浅拷贝是C++中对象拷贝的两种不同方式。
浅拷贝是指将一个对象的数据成员的值复制到另一个对象中,这样两个对象将共享相同的数据。当其中一个对象修改了数据,另一个对象也会受到影响。
深拷贝是指创建一个新的对象,并将原对象的数据成员的值复制到新对象中。新对象和原对象是完全独立的,互不影响。

拷贝构造函数:

引子

在现实世界里,我们有时候会看到双胞胎,他们通常外貌很相似,那么类比到创建对象时,如果已经存在一个创建好的类对象时,能不能用它创建一个一模一样的新对象呢。答案是可以的,并且在C++中专门设定了一个函数来完成这个功能,也就是构造拷贝函数。

定义

拷贝构造函数是构造函数的重载,用于创建一个对象时,以另一个同类型对象作为参数,从而将参数对象的数据成员的值复制给新创建的对象。函数只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰)。

使用注意

1.拷贝构造函数的参数只有一个且必须是类类型对象的引用,如果使用传值方式,编译器会直接报错,因为C++规定自定义类型的传值传参会自动调用拷贝构造函数,此时如果传值传参会引发无穷的递归调用。

class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// Date(const Date d) //错误写法:编译错误,引发无穷递归
Date(const Date& d) // 正确写法
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1);
return 0;
}

递归调用过程如下图所示:在这里插入图片描述
2.未显式定义拷贝构造函数,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,也就是浅拷贝。
所以当类中资源没有涉及到资源申请时,系统默认的拷贝构造函数可以完成拷贝,但是当涉及到资源申请时,需要自己编写拷贝构造函数,因为浅拷贝不能满足要求。

比如说一个类对象s1在堆上申请开辟空间,此时如果用s1默认拷贝构造函数拷贝构造一个新对象s2,此时s1和s2都指向同一块内存空间,当程序退出,s1和s2都要销毁,s2先析构,将该空间释放,但当s1析构时,也会释放该空间,造成堆上同一块内存空间的多次释放,从而使程序崩溃。

3.常见调用场景:
使用已存在对象创建新对象
函数参数类型为类类型对象
函数返回值类型为类类型对象

 class Date
{
public:
 Date(int year, int minute, int day)
 {
 cout << "Date(int,int,int):" << this << endl;
 }
 Date(const Date& d)
 {
 cout << "Date(const Date& d):" << this << endl;
 }
 ~Date()
 {
 cout << "~Date():" << this << endl;
 }
private:
 int _year;
 int _month;
 int _day;
};
Date Test(Date d)
{
 Date tmp(d);
 return tmp;
}
int main()
{
 Date d1(2024,10,8);
 Test(d1);
 return 0;
}

运行结果:

Date(int,int,int):006FFC74
Date(const Date& d):006FFB64
Date(const Date& d):006FFB94
~Date():006FFB64
~Date():006FFB94
~Date():006FFC74

编译器在优化后显示三次构造,三次析构,其实是有4次构造和4次析构:
1.调用构造函数创建d1;
2. Test函数值传递,传参时调用拷贝构造创建d;
3. 调用拷贝函数创建tmp;
4. Test函数以值的方式返回,返回时用tmp拷贝构造临时对象用来返回。

所以为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用就尽量使用引用。

赋值运算符重载函数

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表。

运算符重载:

返回值类型 operator操作符(参数列表)

bool operator==(Date& d1,Date& d2)

注意:

有5个运算符不能重载

.*
::
sizeof
.
?:

重载操作符必须有一个类类型参数,作为类成员函数重载时,第一个参数为隐藏的this,用于内置类型的运算符不可以改变其含义。

赋值运算符重载

class Date
{ 
public :
 Date(int year = 1900, int month = 1, int day = 1)
   {
        _year = year;
        _month = month;
        _day = day;
   }
 
 Date (const Date& d)
   {
        _year = d._year;
        _month = d._month;
        _day = d._day;
   }
 //
 Date& operator=(const Date& d)
 {
 if(this != &d)
       {
            _year = d._year;
            _month = d._month;
            _day = d._day;
       }
        
        return *this;
 }
 private:
 int _year;
 int _month;
 int _day;
 };

注意:

1.重载格式:
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
返回*this :可以连续赋值

2.赋值重载函数只能重载成类的成员函数,不可以重载成全局函数

因为赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了。

3.与拷贝构造类似,用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。内置类型值拷贝,自定义类型调用对应的赋值重载。
同样的,和拷贝构造一样的情况,如果类中涉及到资源的管理,不显示定义,系统默认的赋值运算符重载函数因为只能浅拷贝,可能会造成内存的重复释放,此时必须自己手动实现赋值重载。

前置++和后置++重载

C++为了区分前置++和后置++, 规定后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器会自动传递。

class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 // 前置++:返回+1之后的结果
 // this指向的对象函数结束后不会销毁,可以用引用方式返回提高效率
 Date& operator++()
 {
 _day += 1;
 return *this;
 }

 // 后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1
 // 而temp是临时对象,因此只能以值的方式返回,不能返回引用
 Date operator++(int)
 {
 Date temp(*this);
 _day += 1;
 return temp;
 }
private:
 int _year;
 int _month;
 int _day;
};

取地址及const取地址操作符重载

const成员函数

const修饰的成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

class Date{
public:
//void Print(const Date* this)
void Print() const
{
cout << “year:” << _year << endl;
cout << “month:” << _month << endl;
cout << “day:” << _day << endl << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
const Date d1(2024,10,8);
d1.Print();
}

注意:const对象只能调用const成员函数。const成员函数内不可以调用其他的非const成员函数。

取地址及const取地址操作符重载

这两个成员函数一般用编译器默认生成的就可以了,除非想修改返回的内容。

class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&() const
{
return this ;
}
private :
int _year ;
int _month ;
int _day ;
};

本文到此就结束了,本文主要就C++的拷贝构造函数和运算符重载函数展开叙述,结合上篇文章较为完整地总结了C++的默认成员函数,希望能带给你帮助。

标签:const,--,C++,Date,int,重载,拷贝,day
From: https://blog.csdn.net/2301_78696090/article/details/142503813

相关文章

  • 【斯坦福CS144】Lab3
    一、实验目的完成TCPSender的四个接口。二、实验内容在该实验中,我们需要完成TCPSender的以下四个接口:**fill_window:**TCPSender从ByteStream中读取数据,并以TCPSegement的形式发送,尽可能地填充接收者的窗口。但每个TCP段的大小不得超过TCPConfig::MAXPAYLOAD......
  • 【斯坦福CS144】Lab4
    一、实验目的完成一个网络接口实现。二、实验内容完成一个网络接口实现,其大部分工作是:为每个下一跳IP地址查找(和缓存)以太网地址。而这种协议被称为地址解析协议ARP。三、实验过程在minnow目录下输入gitmergeorigin/check4-startercode获取Lab4用文本编辑器打开./......
  • 逻辑回归LogisticRegression
    一、逻辑回归的基础介绍逻辑回归是一个分类模型它可以用来预测某件事发生是否能够发生。分类问题是生活中最常见的问题:生活中:比如预测上证指数明天是否会上涨,明天某个地区是否会下雨,西瓜是否熟了金融领域:某个交易是否涉嫌违规,某个企业是否目前是否违规,在未来一段时间内是否......
  • 【斯坦福CS144】Lab5
    一、实验目的在现有的NetworkInterface基础上实现一个IP路由器。二、实验内容在本实验中,你将在现有的NetworkInterface基础上实现一个IP路由器,从而结束本课程。路由器有几个网络接口,可以在其中任何一个接口上接收互联网数据报。路由器的工作是根据路由表转发它得到的数据......
  • 51单片机中断与定时器
    一.中断源  INT0  外部中断0    P3^2引脚低电平或者下降沿信号  INT1  外部中断1    P3^3引脚低电平或者下降沿信号  T0    定时器0中断   定时器/计数器0计数回0溢出  T1    定时器1中断   定时器/计数器1计数......
  • Codeforces Round 804 (Div. 2)(C - D)
    CC观察题意,模拟样例,首先\(0\)不能动,因为相邻的\(mex\)会改变,然后\(1\)也是如此,所以我们固定了\(0\)和\(1\),设两个指针\(l\)和\(r\)表示固定的位置,那么此时在他们两个中间的数可以随便移动,假设有\(x\)个空位,那么如果\(2\)在里面,\(2\)的选......
  • 双向栈表
    include<stdio.h>include<stdlib.h>include<stdbool.h>defineMAXSIZE100//定义数组的最大长度typedefstruct{intdata[MAXSIZE];inttop1;//第一个栈的栈顶指针inttop2;//第二个栈的栈顶指针}DoubleStack;//初始化双栈voidinitStack(DoubleStack*s......
  • 2024.10.09 力扣刷题 盛水最多的容器
    题目:这边是参考了B站UP主的思路进行了解答,采用双下标访问的方式进行。如果要水最多的话,一定是高的那端找低的那端,然后算出面积。如果是低的那端找高的那端,那本身下限就在自己身上,所以不从低的端固定不变。附上代码:intmaxArea(std::vector<int>&height){ if(height.empty......
  • The Missing Semester of Your CS Education
    frompixiv前言ThemissingsemesterofyourCSeducation计算机设计的初衷就是任务自动化,然而学生们却常常陷在大量的重复任务中,或者无法完全发挥出诸如版本控制、文本编辑器等工具的强大作用。效率低下和浪费时间还是其次,更糟糕的是,这还可能导致数据丢失或无法完成某些......
  • 实验2
    Task11#include<stdio.h>2#include<stdlib.h>3#include<time.h>45#defineN56#defineN13977#defineN24768#defineN321910intmain(){11intcnt;12intrandom_major,random_no;1314srand(tim......