• 类与对象---砥柱代码练习篇(c++)


    0. 前言

    构造函数、析构函数、拷贝构造、赋值重载、取地址重载-普通对象和const对象取地址。

    像下面这两种就是取地址重载,一般我们使用默认的就可以了,除非你不想让别人找到你的地址这种情况就可以用了。

    class Date
    {
    public :
    	Date* operator&()
    	{
    		return this ;
    	}
    
    	const Date* operator&() const
    	{
    		return this ;
    	}
    private :
    	int _year ; // 年
    	int _month ; // 月
    	int _day ; // 日
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    谈到这里可能,部分友友不知到这段代码什么意思?

    const Date* operator&() const
    
    • 1

    类的成员函数还有一个隐形的this指针,而后面const,就是修饰*this也就是this指向的内容。

    //const Date* operator&(const Date* const this) 
    这只是方便理解,实践中在类内部不要这样写。
    
    • 1
    • 2

    稍微转换一下,变成可读的代码就是这样了。

    划到此处,我们谈谈本章对日期类的应用。

    00. 链接

    链接:类与对象—类的默认成员函数

    01. 日期类的实现–声明

    这个标题内容,写的是日期的大概方向;感兴趣的友友们可以多写几个,例如:日期转换星期,或者写个菜单来感受一番小程序的乐趣。

    写之前注意声明和定义分离,小丁现阶段用的是vs2019
    在这里插入图片描述

    声明–内联函数就直接放在声明里。

    #pragma once
    #include
    #include
    using std::cout;
    using std::endl;
    using std::cin;   //展开部分。
    using std::ostream;
    using std::istream;
    
    //#include
    //using namespace std;  全部展开。
    
    class Date
    {
    public:
    	// 获取某年某月的天数
    	inline int GetMonthDay(int year, int month)
    	{
    		static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    		int day = days[month];
    
    		if ((month == 2) && ((year % 400 == 0) ||
    			(year % 4 == 0 && year % 100 != 0)))
    		{
    			day += 1;
    		}
    
    		return day;
    	}
    
    	//检查输入日期是否合理性。
    	bool CheckDate();
    
    	// 全缺省的构造函数
    	Date(int year = 1900, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    		
    		assert(!CheckDate());
    	}
    
    	// 拷贝构造函数
      // d2(d1)
    	Date(const Date& d);
    
    	// 赋值运算符重载
      // d2 = d3 -> d2.operator=(&d2, d3)
    	Date& operator=(const Date& d);
    
    	// 析构函数
    	~Date();
    
    	// 日期+=天数
    	Date& operator+=(int day);
    
    	// 日期+天数
    	Date operator+(int day) const;
    
    	// 日期-天数
    	Date operator-(int day) const;
    
    	// 日期-=天数
    	Date& operator-=(int day);
    
    	// 前置++
    	Date& operator++();
    
    	// 后置++
    	Date operator++(int);
    
    	// 后置--
    	Date operator--(int);
    
    	// 前置--
    	Date& operator--();
    
    	// >运算符重载
    	bool operator>(const Date& d) const;
    
    	// ==运算符重载
    	bool operator==(const Date& d) const;
    
    	// >=运算符重载
    	bool operator >= (const Date& d) const;
    
    	// <运算符重载
    	bool operator < (const Date& d) const;
    
    	// <=运算符重载
    	bool operator <= (const Date& d) const;
    
    	// !=运算符重载
    	bool operator != (const Date& d) const;
    
    	// 日期-日期 返回天数
    	int operator-(const Date& d) const;
    
    	//打印日期
    	inline void Print() const
    	{
    		cout << _year << '/' << _month << '/' << _day << endl;
    	}
    
    	//友元,可以让它访问私有成员变量。
    	//流插入和流提取没有直接打印或输入的日期,这需要我们来写一个运算符重载。
    	friend ostream& operator<<(ostream& out, const Date& d); //流插入
    	friend istream& operator>>(istream& in, Date& d); //流提取
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    
    inline ostream& operator<<(ostream& out, const Date& d)
    {
    	out << d._year << '/' << d._month << '/' << d._day << endl;
    
    	return out;
    }
    
    inline istream& operator>>(istream& in, Date& d)
    {
    	in >> d._year >> d._month >> d._day;
    
    	return in;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    #include
    using std::cout;
    using std::endl;
    using std::cin;   //展开部分。
    using std::ostream;
    using std::istream;
    
    //#include
    //using namespace std;  全部展开。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    顺便提一下,部分展开比全部展开更安全;只展开常使用的,这是一个较好的习惯。

    友元,可以让它访问私有成员变量。

    friend ostream& operator<<(ostream& out, const Date& d);
    friend istream& operator>>(istream& in, Date& d);

    前面全局函数前面加个friend这个关键字,外面函数就可以访问私有成员变量了。
    注意:

    友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

    这个时候,友友们就会像我直接放在类实现来实现流插入和流提取,确实可以。

    istream& operator>>(istream& in,)
    ostream& operator<<(ostream& out)
    
    • 1
    • 2

    确实可以,可是只能 d1>>d2>>cin d1<

    02. 日期类的实现–构造函数

    构造函数分两种

    //	1.无参构造函数
    Date()
    {}
    //	2.带参构造函数
    Date(int year, int month, int day)
    {
    _year = year;
    _month = month;
    _day = day;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们可以写个缺省函数来玩

    // 全缺省的构造函数
    	Date(int year = 1900, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    		//检查日期是否合法。
    		assert(!CheckDate());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    03. 日期类的实现–拷贝构造函数

    拷贝构造函数就是构造函数的一个重载形式,只有一个参数类型;我们使用类类型的引用。

    // 拷贝构造函数
      // d2(d1)
    Date::Date(const Date& d)  //Date:: 就像一个指示牌,来在类里查找。
    {
    	_year = d._year;
    	_month = d._month;
    	_day = d._day;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    没什么可说的。

    04. 日期类实现–赋值运算符重载

    赋值运算符重载注意不要与拷贝构造函数弄混。
    例子:

    1.Date d1;
    1.Date d2(d1);或者这样写Date d2=d1;
    
    2.Date d1;
    2.Date d2(2022, 7, 26);
    2.d1=d2;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    明显看出1.是拷贝构造函数,2.是赋值运算符重载。

    // 赋值运算符重载
      // d2 = d3 -> d2.operator=(&d2, d3)
    Date& Date::operator=(const Date& d)
    {
    	if (this != &d) //防止出现d1=d1,这种自己给自己的。
    	{
    		_year = d._year;
    		_month = d._month;
    		_day = d._day;
    	}
    
    	return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意:引用的使用和范围。

    05. 日期类实现–日期与天数的加减

    // 日期+=天数
    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 > 12) //十三月份就是,下一年的一月份。
    		{
    			++_year;
    			_month = 1;
    		}
    	}
    
    	return *this;
    }
    
    // 日期+天数
    Date Date::operator+(int day) const
    {
    	Date ret = *this;
    	ret += day;
    
    	return ret;
    }
    
    // 日期-天数
    Date Date::operator-(int day) const
    {
    	Date ret = *this;
    	ret -= day;
    
    	return ret;
    }
    
    // 日期-=天数
    Date& Date::operator-=(int day)
    {
    	if (day < 0)//防止传参传个负数。
    	{
    		return *this += -day;
    	}
    
    	_day -= day;
    	while (_day <= 0)
    	{
    		_day += GetMonthDay(_year, _month);
    		--_month;
    		if (_month == 0)
    		{
    			--_year;
    			_month = 12;
    		}
    	}
    
    	return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    -=或+=都需要返回值,我们使用引用;而且还可以实现-或+的时候复用一下。

    // 前置++
    Date& operator++();
    
    // 后置++
    Date operator++(int);
    
    // 后置--
    Date operator--(int);
    
    // 前置--
    Date& operator--();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    明显看出前置与后置的区别是又没有int,int只是用来区分,想传参也可以传。

    // 前置++
    Date& Date::operator++()
    {
    	*this += 1;
    	return *this;
    }
    
    // 后置++
    Date Date::operator++(int)
    {
    	Date ret = *this;
    	*this += 1;
    	return ret;
    }
    
    // 后置--
    Date Date::operator--(int)
    {
    	Date ret = *this;
    	*this -= 1;
    	return ret;
    }
    
    // 前置--
    Date& Date::operator--()
    {
    	*this -= 1;
    	return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    06. 日期类实现–运算符重载

    // >运算符重载
    bool Date::operator>(const Date& d) const
    {
    	if ((_year > d._year) ||
    		(_year > d._year && _month > d._month) ||
    		(_year > d._year && _month > d._month && _day > d._day))
    	{
    		return true;
    	}
    	
    	return false;
    }
    
    // ==运算符重载
    bool Date::operator==(const Date& d) const
    {
    	if (_year == d._year &&
    		_month == d._month &&
    		_day == d._day)
    	{
    		return true;
    	}
    
    	return false;
    }
    
    // >=运算符重载
    bool Date::operator >= (const Date& d) const
    {
    	return(*this == d) || (*this > d);
    }
    
    // <运算符重载
    bool Date::operator < (const Date& d) const
    {
    	return !(*this >= d);
    }
    
    // <=运算符重载
    bool Date::operator <= (const Date& d) const
    {
    	return !(*this > d);
    }
    
    // !=运算符重载
    bool Date::operator != (const Date& d) const
    {
    	return !(*this == d);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    注意:复用。

    06. 日期类实现–日期减日期并返回天数

    // 日期-日期 返回天数。
    int Date::operator-(const Date& d) const
    {	
    	//找最小和最大
    	Date max = *this;
    	Date min = d;
    	int flag = 1;
    	if (*this < d)
    	{
    		max = d;
    		min = *this;
    		flag = -1;
    	}
    	
    	//统计相差的天数。
    	int n = 0;
    	while (min != max)
    	{
    		++min;
    		++n;
    	}
    	return flag * n;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注意:复用。

    00// 展示:

    最后还有一个判断函数参上:

    //检查日期是否合理
    bool Date::CheckDate()
    {
    	if ((_month > 0 && _month <= 12) ||
    		(_day > 0 && _day <= GetMonthDay(_year, _month)))
    	{
    		return true;
    	}
    
    	return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试用例自己随便写一些,我的测试用例测试后如图:
    在这里插入图片描述
    .
    .
    .
    感觉有所收获的话,友友们给小丁一个赞👍。

  • 相关阅读:
    [C++学习] 多进程通信共享内存
    Android 12(S) 图像显示系统 - 初识ANativeWindow/Surface/SurfaceControl(七)
    智能驾驶开启产业新赛道:资本扎堆布局车规级高精定位
    openGauss gsql 常用元命令 一
    使用BitLocker实现磁盘加密、u盘加密、移动硬盘加密
    TypeScript_Ts简介
    【EMQX】2.1.5 EMQ X 消息服务器功能列表
    非零基础自学Java (老师:韩顺平) 第3章 变量 3.14 布尔类型:boolean && 3.15 基本数据类型转换
    Python自动化必不可少的测试框架 — pytest
    C++ 20 新特性简介
  • 原文地址:https://blog.csdn.net/Dingyuan0/article/details/126003260