题目是,实现一个日期类
要求日期分为年月日
完成默认成员函数
以及可以实现日期类的简单运算(+,+=,前置++,后置++)
一下是C++程序,每一句不同于C的语句都跟有相关注释
包括注释中提到的一些C++概念
#include <iostream> class Date//类可以理解为一种可以放函数的结构体 { ?? ?//公共成员,在函数外可以调用 public: ?? ?//构造函数,名字与类同名,无返回值,建立对象时自动调用,可以重载 ?? ?//? ?? ?// 重载 ?? ?// 指在C++中,可以函数同名,同名的函数因为参数的不同,而区别为不同函数 ?? ?// 因为C中,在连接时函数的符号表名就是函数名,所以不能函数同名 ?? ?// 而在C++中,符号表名不只是函数名还要加上别的所以可以重载 ?? ?//? ?? ?//无参或者全缺省参数也可以认为是默认构造函数 ?? ?//默认写的初始化,只管自定类型(类,结构体等),内置类型(char,int 等)不管 ?? ?Date(int year = 2022, int mouth = 10, int day = 18) ?? ?{ ?? ??? ?//C++有命名空间,在不同命名空间中对象名可以重复 ?? ??? ?//相关关键字namespace可以创建命名空间域 ?? ??? ?// 这个语句using namespace std 可以打开这个std这个命名空间域 ?? ??? ?// 这样在调用这个域中的对象时就可以不用std:: ?? ??? ?// :: 域作限定符 ?? ??? ?// 左边为空默认全局域 ?? ??? ?// std::cout 表示在std这个域中找cout ?? ??? ?// std是C++的标准命名空间域 ?? ??? ?// cout可以认为是屏幕 ?? ??? ?// 当一个工程里的多个文件内有同名命名空间将自动合并 ?? ??? ?//标记 ?? ??? ?std::cout << "flag, init\n" << std::endl; ?? ??? ?_year = year; ?? ??? ?_month = mouth; ?? ??? ?_day = day; ?? ?} ?? ?//~Date析构函数无参无返回值,一个类只能有一个,对象生命周期结束时自动调用 ?? ?//一般的没开辟空间不用自己写,默认的就够用了 ?? ?//但是开辟了空间也不一定要自己写 ?? ?//如果开辟的空间是自定类型,且该自定类型有析构函数 ?? ?//则自动生成的析构函数就可以释放空间 ?? ?//自动调用的析构函数会调用自定类型的析构函数 ?? ?~Date() ?? ?{ ?? ??? ?std::cout << "flag, destroy\n" << std::endl; ?? ??? ?_year = 0; ?? ??? ?_month = 0; ?? ??? ?_day = 0; ?? ?} ?? ?//拷贝构造函数是构造函数的一个重载,有且只有一个参数且必须是 ?? ?//类的引用 ?? ?//? ?? ?//引用,可以理解为对象的别名,必须初始化 ?? ?//底层大概和指针差不多,不能空引用 ?? ?// ?? ?//拷贝构造的参数如果使用传值调用就会无限递归,因为拷贝构造传值调用需要拷贝一次形参 ?? ?// 拷贝形参又调用拷贝构造... ?? ?// ?? ?//如果使用指针来实现拷贝构造 ?? ?//虽然可以实现功能,但是不是拷贝构造,而是构造函数的重载 ?? ?Date(const Date& date) ?? ?{ ?? ??? ?std::cout << "flag, copy\n" << std::endl; ?? ??? ?_year = date._year; ?? ??? ?_month = date._month; ?? ??? ?_day = date._day; ?? ?} // // 运算符重载 // 运算符重载指,使用关键字operator,让自定类型可以使用运算符 //?
?? ?//必须有一个返回值,返回值是运算的结果 ?? ?// 有两个参数(取决于符号的操作数) ?? ?//分别是在使用运算符号时所涉及的操作数 ?? ?//关键字旁边的是重载的运算符 ?? ?// ?? ?//由于此处是Date的成员还是所以还有一个隐藏的this指针 ?? ?// ?? ?//this指针类型,是类类型* const ?? ?//故不能赋值。必须在成员函数内使用 ?? ?//其意义在于,自动指向调用他的类对象 ?? ?//这样就可以保证,同一个类的不同的类对象,使用同一个函数完成调用 ?? ?//即当不同的类对象在调用成员函数时,this指向对应的类对象 ?? ?//this指针是一种形参,只存在于栈帧中 ?? ?// ?? ?//如下,有一个隐藏this指向调用=号的类对象,另一个操作数是显示的参数 ?? ?//此处返回值使用引用是为了能够实现嵌套 ?? ?// 比如(d+=d)+=d ?? ?//参数使用引用,是因为相比传值不用拷贝,相比指针更方便 ?? ?Date& operator= (const Date& d1) ?? ?{ ?? ??? ?//this指针指向调用this的对象,所以此处直接使用成员函数被赋值 ?? ??? ?_year = d1._year; ?? ??? ?_month = d1._month; ?? ??? ?_day = d1._day; ?? ??? ?//返回值是引用所以必须this指针解引用得到对象 ?? ??? ?return *this; ?? ?} ?? ?//?? ?// 日期+=天数 ?? ?// ?? ?Date& operator+= (int day) ?? ?{ ?? ??? ?_day += day; ?? ??? ?while (_day > GetMonthDay(_year, _month))//日期不对则进入 ?? ??? ?{ ?? ??? ??? ?_day -= GetMonthDay(_year, _month); ?? ??? ??? ?_month++; ?? ??? ??? ?if (_month > 12) ?? ??? ??? ?{ ?? ??? ??? ??? ?_year++; ?? ??? ??? ??? ?_month = 1; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?return *this; ?? ?} ?? ?// 日期+天数 ?? ?//加不改变操作数所以不需要引用返回实现可以改变操作数的嵌套调用 ?? ?Date operator+ (int day) ?? ?{ ?? ??? ?Date d1(*this); ?? ??? ?d1._day += day; ?? ??? ?while (d1._day > GetMonthDay(d1._year, d1._month))//日期不对则进入 ?? ??? ?{ ?? ??? ??? ?d1._day -= GetMonthDay(d1._year, d1._month); ?? ??? ??? ?d1._month++; ?? ??? ??? ?if (d1._month > 12) ?? ??? ??? ?{ ?? ??? ??? ??? ?d1._year++; ?? ??? ??? ??? ?d1._month = 1; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?return d1; ?? ?} ?? ?//?? ?// 前置++ ?? ?// 由于如下代码 ?? ?//int main() ?? ?//{ ?? ?//?? ?Age a;
?? ?//?? ?(a++)++; ?//编译错误 ? ?? ?? ?//?? ?++(a++); ?//编译错误 ? ?? ?? ?//?? ?a++ = 1; ? //编译错误 ? ?? ?? ?//?? ?(++a)++; ?//OK ? ?? ?? ?//?? ?++(++a); ?//OK ? ?? ?? ?//?? ?++a = 1; ? //OK ? ?? ?? ?//} ?? ?//要与内置类型保持一致 ?? ?// 需要这么写 ?? ?// 两个++的返回值区别开来 ?? ?//? ?? ?//Age& operator++() //前置++ ? ?? ?? ?//{ ?? ?//?? ?++i; ?? ?//?? ?return *this; ?? ?//}
?? ?//const Age operator++(int) //后置++ ? ?? ?? ?//{ ?? ?//?? ?Age tmp = *this; ?? ?//?? ?++(*this); ?//利用前置++ ? ?? ?? ?//?? ?return tmp; ?? ?//} ?? ?// ?? ?//形参的区别
?? ?//前置++没有形参,而后置++有一个int形参,但是该形参也没有被用到。 ?? ?//?? ?也没有特殊的用意,只是为了绕过语法的限制。 ?? ?//?? ?前置++与后置++的操作符重载函数,函数原型必须不同。 ?? ?// 否则就违反了“重载函数必须拥有不同的函数原型”的语法规定。 ?? ?//?? ?虽然前置++与后置++的返回类型不同,但是返回类型不属于函数原型。 ?? ?//为了绕过语法限制,只好给后置++增加了一个int形参 ?? ?//增加一个double形参而不是int形参,也可以。 ?? ?// ?? ?// 所以我们常说前置++的效率更高 ?? ?// 理由是:即使是内置类型,返回值的不同,让后置++会生成临时对象,影响效率 ?? ?// ?? ?Date& operator++ () //前置++ ? ?? ?? ?{ ?? ??? ?//不能使用_day += 1;因为要构成重载 ?? ??? ?*this += 1; ?? ??? ?return *this; ?? ?}
?? ?const Date operator++ (int) //后置++ ? ?? ?? ?{ ?? ??? ?Date tmp(*this); ?? ??? ?++(*this); ?//利用前置++ ? ?? ?? ??? ?return tmp; ?? ?} ?
// //? // 私有成员,函数外不可调用 private: ?? ?int GetMonthDay(int year,int month) ?? ?{ ?? ??? ?static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; ?? ??? ?if (month == 2) ?? ??? ?{ ?? ??? ??? ?if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ?? ??? ??? ??? ?return 29; ?? ??? ??? ?else ?? ??? ??? ??? ?return 28; ?? ??? ?} ?? ??? ?else ?? ??? ?{ ?? ??? ??? ?return arr[month]; ?? ??? ?} ?? ?} ?? ?int _year; ?? ?int _month; ?? ?int _day; }; int main() { ?? ?Date myold(2022,5,5); ?? ?Date mynew(2022,1,1); ?? ?myold = mynew; ?? ?myold += 50; ?? ?mynew = myold + 38; ?? ?myold = mynew++; ?? ?myold = ++mynew; ?? ?return 0; }
|