【C++】类和对象(中)--下篇

s_little_monster_ 2024-07-14 15:35:01 阅读 52

在这里插入图片描述

个人主页~

类和对象上

类和对象中-上篇


类和对象

五、赋值运算符重载1、运算符重载2、赋值运算符重载3、前置++和后置++重载

六、const成员七、日期类的实现Date.hDate.cpptest.cpptest1测试结果test2测试结果test3测试结果test4测试结果test5测试结果test6测试结果test7测试结果

八、关于取地址和const取地址操作符重载

五、赋值运算符重载

1、运算符重载

运算符重载是具有特殊函数名的函数,是C++为了增强代码可读性而引入的

<code>operator sign(parameter);

operator为关键字,sign就是需要重载的运算符符号,parameter为参数(可以为多个)

注意事项:

不能通过连接其他符号来创建新的操作符

重载操作符至少有一个类类型参数

用于内置类型之间的运算符含义不改变,编译器会自动检测使用运算符的类型是什么,从而选择是否改变运算符含义

类成员函数重载时有一个隐藏的参数this

不能重载的五个运算符
.*
::
sizeof
?:
.

重载一个==

//……全局

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

{

return d1._year == d2._year

&& d1._month == d2._month

&& d1._day == d2._day;

}

//……

但定义一个全局函数需要成员函数公有,所以我们直接定义在类内,保证其封装性

//……类内

bool operator==(const Date& d2)

{

return _year == d2._year

&& _month == d2._month

&& _day == d2._day;

}

//……

2、赋值运算符重载

(1)格式

参数类型 const name& 引用传参

返回值类型 name& 返回引用

检测是否自己给自己赋值

返回*this

(2)赋值运算符的重载

赋值运算符只能重载成类的成员函数不能重载成全局函数

赋值运算符如果不显式实现,编译器会生成一个默认的,此时再在外边实现一个全局的赋值运算符重载,就会发生冲突

class Date

{

public:

Date(int year, int month, int day)

{

_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;

};

(3)用户没有显式实现时,编译器会生成一个默认赋值运算符重载,然后值拷贝,内置成员直接赋值,自定义成员需要调用对应类的赋值运算符重载完成赋值

(4)有了值拷贝我们就一定要说说深拷贝,在Date类这样的类中不需要我们自己实现,而在Stack这样的类中就需要显式实现,进行资源管理

拿出我们的老演员栈:

typedef int DataType;

class Stack

{

public:

Stack(size_t capacity = 10)

{

arr = (DataType*)malloc(capacity * sizeof(DataType));

if (nullptr == arr)

{

perror("malloc申请空间失败");

return;

}

size = 0;

capacity = capacity;

}

void Push(const DataType& data)

{

// CheckCapacity();

arr[size] = data;

size++;

}

~Stack()

{

if (arr)

{

free(arr);

arr = nullptr;

capacity = 0;

size = 0;

}

}

private:

DataType* arr;

size_t size;

size_t capacity;

};

int main()

{

Stack s1;

s1.Push(1);

s1.Push(2);

Stack s2;

s2 = s1;

return 0;

}

在这里插入图片描述

调试后发现又是析构函数这里出了问题,原因同拷贝构造函数:因为编译器自动生成的拷贝构造函数是值拷贝,所以在生成s2时,s2中的指针a指向的数组与s1中的指针指向的数组相同,在程序结束时,调用析构函数释放了s2,对应的这块数组空间也被释放,然后调用析构函数释放s1,已经被释放的空间不能被再次释放,所以出现了这样的错误,所以我们需要自己显式定义一个拷贝构造函数

3、前置++和后置++重载

我们先来复习一下前置++和后置++的区别,在仅自加时也就是在n++为一条语句时没有区别,在赋值时,前置++是先+1后赋值,后置++是先赋值再+1

如果我们想要++重载,那么就是定义operator++,分不出为前置还是后置,所以我们规定operator++为前置++operator++(int)为后置++

<code>class Date

{

public:

Date(int year = 1970, int month = 1, int day = 1)

{

_year = year;

_month = month;

_day = day;

}

Date& operator++()

{

*this += 1;

return *this;

}

Date operator++(int)

{

Date tmp(*this);

*this += 1;

return tmp;

}

//所以后置++会使用空间拷贝,效率比前置++低

void Print()

{

cout << _year << "/" << _month << "/" << _day << endl;

}

private:

int _year;

int _month;

int _day;

};

int main()

{

Date d;

Date d1(2000,1,1);

d = d1++;

d.Print();

d1.Print();

d = ++d1;

d.Print();

d1.Print();

return 0;

}

在这里插入图片描述

六、const成员

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

因为参数为隐藏的,所以我们的方法如下:

<code>void Date::Print() const

{

cout << _year << "/" << _month << "/" << _day << endl;

}

相当于

void Date::Print(const Date* this)

{

cout << _year << "/" << _month << "/" << _day << endl;

}

注意:

const对象不能调用非const成员函数

非const对象能调用const成员函数

const成员函数内不能调用其他非const成员函数

非const成员函数内能调用其他const成员函数

七、日期类的实现

Date.h

#pragma once

#include <iostream>

using namespace std;

class Date

{

public:

int GetMonthDay(int year, int month);

Date(int year = 1970, int month = 1, int day = 1);

Date(const Date& d);

~Date();

Date& operator=(const Date& d);

Date& operator+=(int day);

Date& operator-=(int day);

Date& operator++();

Date operator++(int);

Date& operator--();

Date operator--(int);

Date operator+(int day);

Date operator-(int day);

bool operator==(const Date& d);

bool operator<(const Date& d);

bool operator<=(const Date& d);

bool operator>(const Date& d);

bool operator>=(const Date& d);

bool operator!=(const Date& d);

int operator-(const Date& d);

void Print() const;

private:

int _year;

int _month;

int _day;

};

Date.cpp

#define _CRT_SECURE_NO_WARNINGS

#include "Date.h"

int Date::GetMonthDay(int year, int month)

{

const static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))

{

return 29;

}

return days[month];

}

Date::Date(int year, int month, int day)

{

_year = year;

_month = month;

_day = day;

if (month < 1 || month > 12

|| day < 1 || day > GetMonthDay(year, month))

{

cout << "非法日期" << endl;

exit(-1);

}

}

Date::Date(const Date& d)

{

_year = d._year;

_month = d._month;

_day = d._day;

}

Date::~Date()

{

_year = _month = _day = 0;

}

//日期类的析构函数其实没必要写

Date& Date::operator=(const Date& d)

{

if(this != &d)

{

_year = d._year;

_month = d._month;

_day = d._day;

}

return *this;

}

Date& Date::operator+=(int day)

{

if (day < 0)

{

return *this -= (-day);

}//复用-=

_day += day;

while (_day > GetMonthDay(_year, _month))

{

_day -= GetMonthDay(_year, _month);

++_month;

if (_month == 13)

{

++_year;

_month = 1;

}

}

return *this;

}

Date& Date::operator-=(int day)

{

if (day < 0)

{

return *this += (-day);

}//复用+=

_day -= day;

while (_day <= 0)

{

--_month;

if (_month == 0)

{

--_year;

_month = 12;

}

_day += GetMonthDay(_year, _month);

}

return *this;

}

Date& Date::operator++()

{

*this += 1;

return *this;

}

Date Date::operator++(int)

{

Date tmp(*this);

*this += 1;

return tmp;

}

Date& Date::operator--()

{

*this -= 1;

return *this;

}

Date Date::operator--(int)

{

Date tmp(*this);

*this -= 1;

return tmp;

}

Date Date::operator+(int day)

{

Date tmp(*this);

tmp += day;

return tmp;

}

Date Date::operator-(int day)

{

Date tmp(*this);

tmp -= day;

return tmp;

}

bool Date::operator==(const Date& d)

{

return _year == d._year

&& _month == d._month

&& _day == d._day;

}

bool Date::operator<(const Date& d)

{

if (_year < d._year)

{

return true;

}

else if (_year == d._year && _month < d._month)

{

return true;

}

else if (_year == d._year && _month == d._month && _day < d._day)

{

return true;

}

else

{

return false;

}

}

// d1 <= d2

bool Date::operator<=(const Date& d)

{

return *this < d || *this == d;

}

bool Date::operator>(const Date& d)

{

return !(*this <= d);

}

bool Date::operator>=(const Date& d)

{

return !(*this < d);

}

bool Date::operator!=(const Date& d)

{

return !(*this == d);

}

int Date::operator-(const Date& d)

{

//假设左大右小,此时标识符flag为1

Date max = *this;

Date min = d;

int flag = 1;

//如果左小右大,则置换后置标识符flag为-1

if (*this < d)

{

max = d;

min = *this;

flag = -1;

}

//算出大的与小的之间的天数

int n = 0;

while (min != max)

{

++min;

++n;

}

//返回与标识符flag的乘积

return n * flag;

}

void Date::Print() const

{

cout << _year << "/" << _month << "/" << _day << endl;

}

test.cpp

#define _CRT_SECURE_NO_WARNINGS

#include "Date.h"

//初始化

void test1()

{

Date d1(2000, 1, 1);

d1.Print();

Date d2;

d2.Print();

Date d3 = Date(d1);

d3.Print();

}

//++

void test2()

{

Date d1(2001, 2, 28);

Date d2 = d1++;

Date d3 = ++d1;

}

//+ -

void test3()

{

Date d1(2000, 1, 1);

Date d2 = d1 + 20000;

Date d3 = d1 - 20000;

}

//--

void test4()

{

Date d1(2000, 3, 1);

Date d2 = d1--;

Date d3 = --d1;

}

//+= -=

void test5()

{

Date d1(2000, 1, 1);

d1 += 20000;

Date d2;

d2 -= 20000;

}

//日期-日期

void test6()

{

Date d1(2000, 1, 1);

Date d2;

int a = d1 - d2;

}

//=

void test7()

{

Date d1(2000, 1, 1);

Date d2;

d2 = d1;

}

int main()

{

//test1();

//test2();

//test3();

//test4();

//test5();

//test6();

//test7();

return 0;

}

test1测试结果

在这里插入图片描述

构造和拷贝构造函数正常

test2测试结果

在这里插入图片描述

在这里插入图片描述

前置后置++都正常

test3测试结果

在这里插入图片描述

在这里插入图片描述

+、 - 不改变原来的值,正常

test4测试结果

在这里插入图片描述

在这里插入图片描述

前置后置- -正常

test5测试结果

在这里插入图片描述

-= +=改变原来的数,正常

test6测试结果

在这里插入图片描述

日期减日期为整数正常

test7测试结果

在这里插入图片描述

=赋值正常

全部正常

八、关于取地址和const取地址操作符重载

&

const …… &

这两个一般不用重新定义,编译器会默认生成,如果有别的用途,可以显式定义重载


今日分享结束~

在这里插入图片描述



声明

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