目录
operator++(int)/operator++() 成员函数的实现
operator--(int)/operator--() 成员函数的实现
简介
上一节我们了解了C++的一些基本名词概念,但没有涉及到最为核心的内容,下面我将会介绍一下两个问题:
- 什么是类?
- 什么是对象?
类
在C++中我们一般使用单词class来代表类,类里面分为三个限定访问符:公有(public)、私有(private)、受保护的(protected)。
类中的内容称为类的成员,类中的变量称为类的属性或者成员变量,类中的函数称为类的方法或者成员函数。
下面我用一段代码,定义一个类:
#include<iostream>
using namespace std;
class TestDate
{
public:
void InitDate(int year)
{
year = _year;
}
private:
int _year;//一般需要加个前缀,便于区分
};
对象
对象,是一个物体或者说事物。我们用一个类去描述一个对象,类里面的函数,就代表了这个物体的使用方法,类中的变量就代表了我们能够如何调用这个物体,让这个物体运行起来。这些函数就被称为接口,与外界相连,一般也放在public里,而那些变量则被存放在private里面。还有一些很重要的就被丢到protected里。
这个过程就被称为类实例化对象。
日期类
我们通过实现一个日期类来了解类和对象,以及类和对象其中的一些细枝末节的语法内容。
我们采用了声明定义分离的方式来实现日期类,一个是方便阅读理解, 一个是更加规范。
定义部分
下面我们首先看一下声明文件(Date.h),这一部分负责的是函数的定义部分。
#pragma once
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 2024, int month = 1, int day = 1);//全缺省构造函数
int Get(int year, int month);//获取当前年份以及月份
Date(const Date& d);//拷贝构造函数->为了防止数据被修改
void Print();//打印函数
~Date();//销毁函数
Date operator=(const Date& d);//运算符=重载->赋值(含义是将年份赋给d.year,月份赋给d.month,日赋给d.day)
Date& operator+=(int day);
Date operator+(int day);
Date operator-(int day);
Date& operator-=(int day);
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
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);
private:
int _year;
int _month;
int _day;
};
实现部分
然后我们看一下函数的实现部分,Date.cpp。
构造函数部分
Date::Date(int year, int month, int day)
{
if (month < 1 || month>12 || day<1 || day>Get(year, month))
{
cout << "日期非法" << endl;
}
_year = year;
_month = month;
_day = day;
}
函数接受三个参数:年year、月和日day。首先,函数检查month和day的值是否合法,即month必须在1到12之间,day必须在1到该月最大天数之间。如果非法,函数将输出错误信息"日期非法"。如果参数合法,则将year、month和day的值分别赋值给_year、_month和_day三个成员变量。这个构造函数用于创建一个新的日期对象,并确保其日期是有效的。
获取给定年份和月份的天数
int Date::Get(int year, int month)
{
int Array[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)) //判断闰年
{
Array[2]++;
}
return Array[month];//返回当前月份的天数。
}
打印年份月日
void Date::Print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
拷贝构造函数
拷贝构造函数是一种特殊的构造函数,它用于创建一个新对象,作为另一个同类型对象的副本。在这个例子中, Date::Date(const Date& d) 接收一个对 Date 类型对象的常量引用 d 作为参数,并将新对象的年( _year )、月( _month )、日( _day )成员变量分别初始化为参数对象 d 的对应成员变量的值。
拷贝构造函数的主要用途包括
- 对象复制:当你需要将一个已存在的对象赋值给同类型的另一个新对象时,拷贝构造函数会被自动调用。
- 函数参数传递:当对象作为值传递给函数时,会调用拷贝构造函数来创建函数内部使用的对象副本。
- 函数返回值:当函数返回对象时(特别是返回局部对象时),会调用拷贝构造函数来创建并返回对象的副本给调用者。
拷贝构造函数需要正确处理对象的深拷贝和浅拷贝问题,以避免出现悬挂指针、重复释放内存等错误。然而,在 Date 类的这个例子中,由于它只包含基本数据类型( int 类型的年、月、日),所以不需要担心这些问题。
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
析构函数
析构函数用于销毁函数。
Date::~Date() {}
拷贝赋值运算符( operator= )的实现
这段代码是 Date 类的拷贝赋值运算符( operator= )的实现。拷贝赋值运算符是一个特殊的成员函数,用于将一个 Date 类型的对象赋值给另一个 Date 类型的对象。
Date Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return*this;
}
operator+= 成员函数的实现
这段代码是 Date 类的 operator+= 成员函数的实现,用于实现日期加上一定天数的操作。
函数接收一个 int 类型的参数 day ,表示要加上的天数。如果 day 小于 0,函数会调用 operator-= 成员函数(通过将 day 取负)来实现日期减去一定天数的操作。
如果 day 大于等于 0,函数会将 _day 成员变量加上 day ,表示日期加上一定天数。然后,函数会检查 _day 是否大于当前月份的最大天数。如果是,函数会进入一个循环,将 _day 减去当前月份的最大天数,并将 _month 成员变量加 1,表示日期进入了下一个月份。
如果 _month 等于 13,表示日期进入了下一年份,函数会将 _month 重置为 1,并将 _year 成员变量加 1,表示日期进入了下一年份。
最后,函数返回 *this ,即当前对象的引用,使得该函数可以链式调用。
Date& Date::operator+=(int day)
{
if (day < 0)
{
*this -= (-day);
return *this;
}
_day += day;
while (_day > Get(_year, _month))
{
//月进位
_day -= Get(_year, _month);
++_month;
//年进位
if (_month == 13)
{
++_year;
_month = 1;
}
}
return*this;
}
operator+ 成员函数的实现
这段代码是 Date 类的 operator+ 成员函数的实现,用于实现日期加上一定天数的操作。
函数接收一个 int 类型的参数 day ,表示要加上的天数。如果 day 小于 0,函数会调用 operator- 成员函数(通过将 day 取负)来实现日期减去一定天数的操作,然后将结果返回。
如果 day 大于等于 0,函数会创建一个新的 Date 对象 tmp ,并将其初始化为当前对象的拷贝。然后,函数会使用 operator+= 成员函数(通过将 day 加到 tmp 对象上)来实现日期加上一定天数的操作。最后,函数将 tmp 对象返回,表示新的日期。
这种实现方式避免了在 operator+ 函数中直接修改当前对象的状态,而是创建了一个新的 Date 对象来保存结果,这使得 Date 类更加符合不可变性原则,即一个对象的状态在其生命周期内不应该被改变。
Date Date::operator+(int day)
{
if (day < 0)
{
return *this - (-day);
}
Date tmp(*this); //拷贝构造
tmp += day; //复用+=运算符
return tmp;
}
operator- 成员函数
这段代码是 Date 类的 operator- 成员函数的实现,用于实现日期减去一定天数的操作。
函数接收一个 int 类型的参数 day ,表示要减去的天数。函数首先创建一个新的 Date 对象 tmp ,并将其初始化为当前对象的拷贝。然后,函数会使用 operator-= 成员函数(通过将 day 减到 tmp 对象上)来实现日期减去一定天数的操作。最后,函数将 tmp 对象返回,表示新的日期。
这种实现方式避免了在 operator- 函数中直接修改当前对象的状态,而是创建了一个新的 Date 对象来保存结果,这使得 Date 类更加符合不可变性原则,即一个对象的状态在其生命周期内不应该被改变。
Date Date::operator-(int day)
{
Date tmp = *this;
tmp -= day;
return tmp;
}
operator-= 成员函数的实现
这段代码是 Date 类的 operator-= 成员函数的实现,用于实现日期减去一定天数的操作。
函数接收一个 int 类型的参数 day ,表示要减去的天数。如果 day 小于 0,函数会调用 operator+= 成员函数(通过将 day 取负)来实现日期加上一定天数的操作。
如果 day 大于等于 0,函数会将 _day 成员变量减去 day ,表示日期减去一定天数。然后,函数会检查 _day 是否小于等于 0。如果是,函数会进入一个循环,将 _month 成员变量减 1,表示日期进入了上一个月份。
如果 _month 等于 0,表示日期进入了上一年份,函数会将 _month 重置为 12,并将 _year 成员变量减 1,表示日期进入了上一年份。
然后,函数会将 _day 加上当前月份的最大天数,表示日期进入了上一个月份的最后一天。
最后,函数返回 *this ,即当前对象的引用,使得该函数可以链式调用。
Date& Date::operator-=(int day)
{
if (day < 0)
{
*this += (-day);
return *this;
}
_day -= day;
while (_day <= 0)
{
//月让位
--_month;
//年让位
if (_month == 0)
{
--_year;
_month = 12;
}
_day += Get(_year, _month);
}
return *this;
}
operator++(int)/operator++() 成员函数的实现
这段代码是 Date 类的 operator++(int) 成员函数的实现,用于实现日期增加一天的操作。
函数接收一个 int 类型的参数,但未使用。这个参数是 operator++(int) 的后置版本( operator++(int) )使用的,用于区分前置版本( operator++() )和后置版本。
函数首先创建一个 Date 类的临时对象 tmp ,并将其初始化为当前对象的拷贝。然后,函数调用 operator+= 成员函数,将当前日期增加一天。最后,函数返回 tmp ,即增加一天前的日期对象。
注意,该函数的实现依赖于 Date 类的 operator+= 成员函数,该函数用于实现日期加上一定天数的操作。因此,在实际使用中,需要确保 operator+= 函数已经被正确实现
Date& Date::operator++()
{
*this += 1; //先+1
return *this; //再返回,返回+1后的结果
}
Date Date::operator++(int)
{
Date tmp(*this); //拷贝一份
*this += 1; //然后+1
return tmp; //返回+1前的结果
}
operator--(int)/operator--() 成员函数的实现
这段代码是 Date 类的 operator--() 成员函数的实现,用于实现日期减少一天的操作。
函数接收一个 int 类型的参数,但未使用。这个参数是 operator--(int) 的后置版本( operator--(int) )使用的,用于区分前置版本( operator--() )和后置版本。
函数首先创建一个 Date 类的临时对象 tmp ,并将其初始化为当前对象的拷贝。然后,函数调用 operator-= 成员函数,将当前日期减少一天。最后,函数返回 tmp ,即减少一天前的日期对象。
Date& Date::operator--()
{
*this -= 1; //先-1
return *this; //再返回,返回-1后的结果
}
Date Date::operator--(int)
{
Date tmp(*this); //拷贝一份
*this -= 1; //然后-1
return tmp; //返回-1前的结果
}
operator>() 成员函数的实现
这段代码是 Date 类的 operator>() 成员函数的实现,用于实现日期的比较操作。
函数接收一个 const Date& 类型的参数 d ,表示要比较的日期对象。
函数首先比较当前对象的年份 _year 和参数对象 d 的年份 _year 。如果当前对象的年份大于参数对象的年份,函数返回 true ,表示当前日期比参数日期晚。
如果当前对象的年份等于参数对象的年份,函数会比较当前对象的月份 _month 和参数对象 d 的月份 _month 。如果当前对象的月份大于参数对象的月份,函数返回 true ,表示当前日期比参数日期晚。
如果当前对象的年份和月份都等于参数对象的年份和月份,函数会比较当前对象的日期 _day 和参数对象 d 的日期 _day 。如果当前对象的日期大于参数对象的日期,函数返回 true ,表示当前日期比参数日期晚。
如果前面的条件都不符合,说明当前日期比参数日期早,函数返回 false 。
operator==() 成员函数的实现
这段代码是 Date 类的 operator==() 成员函数的实现,用于实现日期的相等性比较操作。
函数接收一个 const Date& 类型的参数 d ,表示要比较的日期对象。
函数使用逻辑与运算符 && 将三个条件连接在一起:
当前对象的年份 _year 等于参数对象 d 的年份 _year 。
当前对象的月份 _month 等于参数对象 d 的月份 _month 。
当前对象的日期 _day 等于参数对象 d 的日期 _day 。
如果这三个条件都成立,即当前日期与参数日期的年份、月份和日期都相等,函数返回 true ,表示当前日期等于参数日期。
否则,如果这三个条件中的任何一个条件不成立,即当前日期与参数日期的年份、月份或日期至少有一个不相等,函数返回 false ,表示当前日期不等于参数日期。
bool Date::operator==(const Date& d)
{
return (_year == d._year) && (_month == d._month) && (_day == d._day);
}
operator<() 成员函数的实现
这段代码是 Date 类的 operator<() 成员函数的实现,用于实现日期的比较操作。
函数接收一个 const Date& 类型的参数 d ,表示要比较的日期对象。
函数使用逻辑非运算符 ! 将 (*this == d) || (* this > d) 的结果取反。
(*this == d) 表示当前日期是否等于参数日期, (* this > d) 表示当前日期是否大于参数日期。
如果 (*this == d) 为 true ,表示当前日期等于参数日期,如果 (* this > d) 为 true ,表示当前日期大于参数日期。
因此, (*this == d) || (* this > d) 表示当前日期等于参数日期或者当前日期大于参数日期。
取反操作 ! 将 (*this == d) || (* this > d) 的结果取反,即如果当前日期等于参数日期或者当前日期大于参数日期,结果为 false ;否则,结果为 true 。
也就是说, !((*this == d) || (* this > d)) 的结果为 true ,当且仅当当前日期既不等于参数日期,也不大于参数日期。
因此, Date::operator<(const Date& d) 函数的返回值表示当前日期是否小于参数日期。如果当前日期小于参数日期,函数返回 true ;否则,返回 false 。
bool Date::operator<(const Date& d)
{
return !((*this == d) || (*this > d)); //逻辑非之后表示既不大于也不等于
}
operator>= 成员函数的实现
这段代码是 Date 类的 operator>= 成员函数的实现,用于实现日期的比较操作。
函数接收一个 const Date& 类型的参数 d ,表示要比较的日期对象。
函数使用逻辑非运算符 ! 将 (*this < d) 的结果取反。
(* this < d) 是 Date::operator<(const Date& d) 函数的调用,用于判断当前日期是否小于参数日期。
如果 (*this < d) 为 true ,表示当前日期小于参数日期,取反后结果为 false ;否则,结果为 true 。
因此, !(* this < d) 的结果为 true ,当且仅当当前日期不小于参数日期。
也就是说, Date::operator>=(const Date& d) 函数的返回值表示当前日期是否大于等于参数日期。如果当前日期大于等于参数日期,函数返回 true ;否则,返回 false 。
bool Date::operator>=(const Date& d)
{
return !(*this < d); //复用<运算符
}
operator<= 成员函数的实现
这段代码是 Date 类的 operator<= 成员函数的实现,用于实现日期的比较操作。
函数接收一个 const Date& 类型的参数 d ,表示要比较的日期对象。
函数使用逻辑非运算符 ! 将 (*this > d) 的结果取反。
(* this > d) 是 Date::operator>(const Date& d) 函数的调用,用于判断当前日期是否大于参数日期。
如果 (*this > d) 为 true ,表示当前日期大于参数日期,取反后结果为 false ;否则,结果为 true 。
因此, !(* this > d) 的结果为 true ,当且仅当当前日期不大于参数日期。
也就是说, Date::operator<=(const Date& d) 函数的返回值表示当前日期是否小于等于参数日期。如果当前日期小于等于参数日期,函数返回 true ;否则,返回 false 。
bool Date::operator<=(const Date& d)
{
return !(*this > d); //复用>运算符
}
operator!= 成员函数的实现
这段代码是 Date 类的 operator!= 成员函数的实现,用于实现日期的不相等比较操作。
函数接收一个 const Date& 类型的参数 d ,表示要比较的日期对象。
函数使用逻辑非运算符 ! 将 (*this == d) 的结果取反。
(* this == d) 是 Date::operator==(const Date& d) 函数的调用,用于判断当前日期是否等于参数日期。
如果 (*this == d) 为 true ,表示当前日期等于参数日期,取反后结果为 false ;否则,结果为 true 。
因此, !(* this == d) 的结果为 true ,当且仅当当前日期不等于参数日期。
也就是说, Date::operator!=(const Date& d) 函数的返回值表示当前日期是否不等于参数日期。如果当前日期不等于参数日期,函数返回 true ;否则,返回 false
bool Date::operator!=(const Date& d)
{
return !(*this == d); //复用==运算符
}
operator- 成员函数的实现
这段代码是 Date 类的 operator- 成员函数的实现,用于实现l两个日期的相减操作。(相当于函数重载了)
函数接收一个 const Date& 类型的参数 d ,表示要减去的日期对象。
函数首先假设当前日期 *this 较小,将当前日期赋值给 min ,将参数日期 d 赋值给 max ,并将 flag 初始化为 -1 ,用于表示最后相减结果的符号。
然后,函数判断假设是否成立。如果 min > max ,表示假设不成立,函数将 min 和 max 互换,并将 flag 设为 1 。
接下来,函数使用 while 循环,将 min 累加,直到 min 大于等于 max 。
最后,函数返回 ret * flag ,其中 ret 表示 min 累加的次数, flag 表示相减结果的符号。
也就是说, Date::operator-(const Date& d) 函数的返回值表示当前日期与参数日期之间的天数差。如果当前日期大于参数日期,返回值为正数;否则,返回值为负数。
int Date::operator-(const Date& d)
{
//找出较小的那个日期,这里先假设*this较小
Date min = *this;
Date max = d;
int flag = -1; //用于表示最后相减结果的符号
if (min > max) //假设不成立,互换
{
min = d;
max = *this;
flag = 1;
}
//小的进行累加,直到二者相等
int ret = 0; //统计min累加的次数
while (max > min)
{
min++;
ret++;
}
return ret * flag; //最终累加的次数即为日期差
}
测试部分
Test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include"Date.h"
using namespace std;
int main()
{
Date d1(2019, 9, 18);
d1.Print();
Date d2;
d2 = d1 + 66;
d2.Print();
Date d3;
d3 += 66;
d3.Print();
Date d4;
d4 = d1 - 66;
d4.Print();
system("pause");
return 0;
}