C++面向对象程序设计之类与对象(2)

1. 拷贝构造函数与赋值重载

 

#include<iostream>

using namespace std;
class Date{
public:
	Date(int year,int month,int day);
	~Date();
	Date(const Date& d);
	Date& operator=(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

//构造函数
Date::Date(int year, int month, int day)
{
	cout << "Date(int year, int month, int day)" << endl;
	_year = year;
	_month = month;
	_day = day;
}

//析构函数
Date::~Date()
{
	cout << "~Date()" << endl;
	_year = 0;
	_month = 0;
	_day = 0;
}

//拷贝构造函数
Date::Date(const Date& d)
{
	cout << "Date(const Date& d)" << endl;
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

//赋值重载
Date& Date::operator=(const Date& d)
{
	cout << "Date operator=(const Date& d)" << endl;
	_year = d._year;
	_month = d._month;
	_day = d._day;

	return *this;
}

int main()
{
	Date d1(2024, 7, 19);
	Date d2(2024, 7, 20);

	//赋值重载
	d1 = d2;

	//拷贝构造
	Date d3 = d2;
	Date d4(d2);

	return 0;
}

2. 运算符重载

关于运算符重载我们这里使用一个实际的日期类 Date 来进行讲解,首先注意定义与声明分离,所以创建头文件 Date.h 与源文件 Date.cpp

之后需要重载的运算符分别有: > >= < <= == != + += - -= 前置++ 后置++ 前置-- 后置-- 日期之差

a. 运算符重载需要用到的关键字是: operator 重载的目的是满足类对象之间的特殊运算,比如两        日期相减求其中相隔的天数

b. 运算符重载实际上就是函数,不过是一种特殊的函数

c. 当然并不是所有运算符都可以重载,以下五种运算符无法重载:

     1  . (点运算符)通常用于去对象的成员,但是->(箭头运算符),是可以重载的
 
     2  :: (域运算符)即类名+域运算符,取成员,不可以重载
 
     3  .* (点星运算符,)不可以重载,成员指针运算符".*,即成员是指针类型
 
     4  ?: (条件运算符)不可以重载
 
     5  sizeof 不可以重载

2.1 Date.h 

在后续的重载时需要频繁调用每一个月的天数,所以创建一个内联函数 GetMonthDay 来获取每一个月的天数,当然内联函数直接定义在类内部,声明与定义不能分离,关键字inline可以省略,默认为内联函数

在之后的重载中有些返回类型是传值有些则是传引用,区别在于

1. 传引用是要改变自己本身,而传值返回不用改变自身

2. 传值返回的是形参的拷贝的一个临时对象,需要调用拷贝构造函数

3. 引用返回可以减少拷贝次数,但是注意当函数中的数据在出函数时未销毁才可以引用(跳出作用      域未被析构)否则就会导致野引用,所以要慎用,当然也可以设置静态变量 static 或者 malloc /      new 的数据

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
	//友元函数
	friend ostream& operator<<(ostream& out,const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1);
	void Print();
	//内联函数直接定义在类内部,声明与定义不能分离,关键字inline可以省略,默认为内联函数
	static int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		int MonthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			MonthDayArray[2]++;
		}

		return MonthDayArray[month];
	}

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

	//传引用是要改变自己本身,而传值返回不用改变自身
	Date operator+(int day);
	Date operator-(int day);

	Date& operator+=(int day);
	Date& operator-=(int day);

	//++d1 -> d1.operator++()
	Date& operator++();

	//d1++ -> d1.operator++(1)
	//为了区分后置++,强行增加了一个参数int
	//一般不用写形参名,只是用来区分前置++与后置++
	Date operator++(int);

	Date& operator--();
	Date operator--(int);

	//两年相差
	int operator-(const Date& d);
private:

	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
2.2 Date.cpp
一、日期与固定天数的运算

1. + 与 +=

重载 += 需要对原日期进行改变所以传引用返回,重载 + 则传值返回,首先实现 += ,将所要加的日期与原日期相加,然后使用 GetMonthDay 内联函数将天数向月数进位再向年数进位,最终返回 this 指针的解引用 *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)
{
	Date tmp = *this;
	//运算符重载
	tmp += day;
	return tmp;
}

2. - 与 -=

与重载 += 和 + 相同,-= 与 - 同样是先实现 -= 再复用重载 -

Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
	    {
			_month = 12;
			_year--;
	    }
		_day += GetMonthDay(_year, _month);
	}
	
	return *this;
}


Date Date::operator-(int day)
{
	Date tmp = *this;
	//运算符重载
	tmp -= day;
	return tmp;
}

3. 前置++ 与 后置++

由于前置与后置运算符均相同,所以在任意一个重载函数名括号内加上数据类型以区分前置与后置的区别,由于前置++是先++后运算,后置++是先运算后++,所以一个需要改变自身的值,一个不用,则前置++传引用返回,后置++传值返回

//前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//后置++
Date Date::operator++(int)
{
	Date tmp(*this); //Date tmp = *this;
	*this += 1;
	return tmp;
}

4. 前置-- 与后置--

与前置++和后置++原理相同

//前置--
Date& Date::operator--()
{
	*this += 1;
	return *this;
}
//后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	//Date tmp(*this);
	*this += 1;
	return tmp;
}
二、日期与日期之间的运算

1. > 与 >= 和 <  与 <=

只进行比较运算,因此不用改变自身的值,传值返回即可

首先只重载 > 即可,重载完成后 >= < <= 均直接复用 > 的逻辑,减少不必要的操作

bool Date::operator>(const Date& d)
{
	int sum = _year * 365 + _month * 31 + _day;
	int count = d._year * 365 + d._month * 31 + d._day;

	if (sum <= count)
	{
		return false;
	}

	return true;
}

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);
}

2. == 与 !=

同样的先重载 == ,之后 != 直接复用即可

bool Date::operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}

3. 两日期之差

首先找出较大日期与较小日期,之后按照日期的逻辑进行相减得出相差的天数即可

int Date::operator-(const Date& d)
{
	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;
}
三、日期类的输入输出

//友元函数
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

istream& operator>>(istream& in, Date& d)
{
	cout << "请依次输入年月日>" << endl;
	in >> d._year >> d._month >> d._day;
	return in;
}

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值