当前位置: 首页 > news >正文

cpp03:小项目Da

//对于日期类,构造需要自己实现,否则没办法初始化。析构和拷贝构造,赋值重载不需要,因为没有资源释放。 

作业:


class Date
{//返回值是什么 就看表达式的结果是什么// d1 + 100;     日期+天数Date operator+(int day) const;// d1 - 100;     日期-天数Date operator-(int day) const;// d1 - d2;       天数-天数=中间差了多少天int operator-(const Date& d) const;private:int _year;int _month;int _day;
}//函数重载:函数名相同,参数不同
//运算符重载:重新定义运算符的行为 
//二者没有直接关系

-------------------------------------------------------------------------------------------------------------------------------

1)声明和定义分离:

一旦把成员函数定义写到类外,就必须加类域限定符 类名::,否则编译器当成普通全局函数处理,链接时会报 “未定义引用”。

Data.h//
class Date 
{
public:Date(int year = 1900, int month = 1, int day = 1);void Print();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);------------------------------------------------------------------------------//定义在类(class/struct都是定义类,只是默认限定符不同)里面的函数,默认是inline。int GetMonthDay(int year, int month) {//[13] 不是笔误,而是故意多开一个元素,把 “第 0 个月” 当成哨兵位(dummy entry),这样数组下标 直接对应真实月份,使用时不用再写 month-1,代码更直观,也省去一次减法运算。//把数组定义成静态的,这样每次调用这个函数的时候就不用重新在栈帧种创建数组,而是直接放在静态区,出了函数也不会销毁。assert(month > 0 && month < 13);static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };//接下来的问题就是2月的问题了,判断闰年时候单独改成29.if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) )return 29;return monthDayArray[month];}
------------------------------------------------------------------------------Date operator+(int day);Date& operator+=(int day);Date operator-(int day);Date& operator-=(int day);private:int _year;int _month;int _day;
};

---------------------------------------------------------------------------------------------------------------------------------

2)日期+天数:满了需要进位,且不止进位一次可能(天满->进位月->月满->进位年)。

问题:要确定每个月的天数。int GetMonthDay(int year, int month)

Data.c//
#include "Date.h"
// 必须写 Date:: 指明这是 Date 类的作用域
Date::Date(int year, int month, int day)
{     _year=year;_month=month;_day=day; 
}void Date::Print() 
{cout << _year << "_" << _month << "_" << _day << endl;
}----------------------------------------------------------------------//出了作用域*this还在,所以可以用Date& 。
//d1+=100 , 实现+=,可以改变自己(d1)。
Date& Date::operator+=(int day) 
{_day += day;    while (_day > GetMonthDay(_year, _month)) //是否超过当前月份的天数{_day -= GetMonthDay(_year, _month);    //如果超过了,减掉当前月的天数(相对于当前月过完)++_month;if (_month == 13) //如果月满了{_year++;    _month = 1;}}return *this;
}
//this指针指向Date的地址,解引用后也就是Date本身,返回其别名。----------------------------------------------------------------------//d1+100 , 实现+,不可以改变自己(d1)。
Date Date::operator+(int day)
{Date tmp = *this;    //+不能改变自己,所以得拷贝一份出来,整个的+,+到tmp上面去。tmp._day += day;while (tmp._day > GetMonthDay(tmp._year, tmp._month)){tmp._day -= GetMonthDay(tmp._year, tmp._month);++tmp._month;if (tmp._month == 13){tmp._year++;tmp._month = 1;}}    return tmp; //tmp:局部对象,出来就销毁了,所以只能用传值返回
}----------------------------------------------------------------------
//+的写法2:用+复用+=。
Date Date::operator+(int day)
{Date tmp = *this;tmp += day;    //拷贝的对象 直接调用上面写的成员函数的+=return tmp;
}
int main()
{Date d1(2024, 7, 12);    //实例化对象d1Date d2 = d1 + 100;   // 等价于 Date d2(d1 + 100);//d1 + 100是调用算符重载函数的写法(step1);//Date d2 = xxx/Date d2(xxx) (step2):调用拷贝构造d1.Print();           // 打印原始 d1d2.Print();           // 打印 d1+100 后的新日期d1 += 100;            // 将 d1 自身再加 100 天d1.Print();           // 打印修改后的 d1return 0;
}

------------------------------------------------------------------------------------------------------------------------------

3)日期 - 天数:借位逻辑。(借的是上一个月的) 
//先写 -=
Date& Date::operator-=(int day)
{_day -= day;while (_day <= 0)    //不合法,需要借位(月)减出来是负数 / 0 :借位。(比如说7月借6月的,而6月是30天){--_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;
}

void TestDate2()
{Date d1(2024, 7, 12);d1 -= 200;
//d1 -= 200; 这条语句会被编译器翻译成 d1.operator-=(200);
//因此唯一被调用的函数就是类成员运算符重载:Date& Date::operator-=(int day);d1.Print();
}int main()
{TestDate2();return 0;
}

-------------------------------------------------------------------------------------------------------------------------------

//-=复用-:
Date Date::operator-(int day)
{Date tmp = *this;   // 1. 拷贝一份tmp._day -= day;    // 2. 先直接把天数减掉// 3. 若天数减到 ≤0,向前借月/年while (tmp._day <= 0){--tmp._month;if (tmp._month == 0)          // 跨年了{tmp._month = 12;--tmp._year;}tmp._day += GetMonthDay(tmp._year, tmp._month);}return tmp;   // 4. 返回减完后的新日期
}
// d1 -= 100Date& Date::operator-=(int day)
{/*Date tmp = *this - day;    //*this:d1*this = tmp;*/     // *this = *this - day; // return *this;        // 
}

-------------------------------------------------------------------------------------------------------------------------------

4)日期大小的比较:

<的正确写法:

//d1<d2:左操作数是this,右操作数是参数.
bool Date::operator<(const Date& d)
{if (_year < d._year)return true;else if (_year == d._year){if (_month < d._month)return true;else if (_month == d._month)return _day < d._day;}return false;
}

>的写法1:

bool Date::operator>(const Date& d)
{if (_year > d._year)return true;else if (_year == d._year){if (_month > d._month)return true;else if (_month == d._month)return _day > d._day;}return false;
}

通用写法:(复用上面写过的函数)

bool Date::operator==(const Date& d)
{return _year == d._year&& _month == d._month&& _day == d._day;
}
// 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);
}

5)日期大小的++:

//二元:一左一右

//一元:

d1++;               // 后置++
Date operator++(int);   ++d1;               // 前置++
Date& operator++();     //这两个函数不能同时存在,因为无法区分。针对这个问题,cpp提出一种规定:(如下)
//建议多用前置,因为前置会返回++后的值,函数就可以传引用返回。

//由于CPP的规定,所以代码写成:
// d1++;
d1.operator++(0);     // 后置++,编译器传0作哑参
Date operator++(int); // 后置自增原型// ++d1;
d1.operator++();      // 前置++
Date operator++();    // 前置自增原型
// d1++;
// d1.operator++(0);
Date Date::operator++(int)   // 后置++
{Date tmp = *this;  // 拷贝一份给tmp,保存原值 拷贝1*this += 1;        // *this 复用Date类的+=return tmp;        // 返回原值 传值返回,拷贝2
}
// ++d1;
// d1.operator++();
Date& Date::operator++()   // 前置++
{*this += 1;   // 自身先加1return *this; // 返回加1后的自身引用
}

前置++先加后用,返回自身引用;后置++先用后加,返回原值副本。

void TestDate2()
{/*Date d1(2024, 7, 13);d1 -= 30000;d1.Print();*/Date d1(2024, 7, 13);Date ret1 = d1++;   // 后置++ret1.Print();       // 打印原值d1.Print();         // 打印加1后的值Date d2(2024, 7, 13);Date ret2 = ++d2;   // 前置++ret2.Print();       // 打印加1后的值d2.Print();         // 打印加1后的值
}

6)日期做差:
// d1 - d2
int Date::operator-(const Date& d)
{int flag = 1;Date max = *this;Date min = d;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;
}
void TestDate4()
{Date d1(2024, 7, 12);Date d2(2024, 9, 1);cout << (d1 - d2) << endl;
}int main()
{TestDate4();return 0;
}
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (!CheckDate())          // 假设 CheckDate() 返回 true 表示合法{cout << "非法日期:" << endl;Print();               // 打印出出错日期}
}

实现方式2:输入d1 d2来实现作差(scanf)

scanf printf直接适用的是内置类型(%d int这种),没办法很好支持自定义类型(类,结构体),只能拆分。

cin(ostream类型的对象),cout(istream类型的对象)直接适用内置类型(%d int这种),因为库里面已经重载好了,能自动识别类型是源自于函数重载从而直接输出;对于自定义类型的支持,需要重载函数。

//cin  cout  输出内置类型:
void TestDate4()
{int i=0;int d1=0;std::cout << i << d;  //本质是转为上述重载好的函数调用,然后返回iostream类型
}
//cin cout输出自定义类型,需要重载函数。重载后遇到这个运算符会自动去调用。
void TestDate4()
{Date d1, d2;cin >> d1 >> d2;  cout << d1 << d2;  
}
// d1 - d2
int operator-(const Date& d);void operator<<(ostream& out);private:
int year;
int month;
int day;
}

1)Date::operator<<(ostream& out)作为成员函数:

则只能写成控制台流向日期类。

void Date::operator<<(ostream& out)
{out << _year << "年" << _month << "月" << _day << "日" << endl;
}
void TestDate5()
{Date d1, d2;// cin >> d1 >> d2;// cout << d1 << d2;cout << d1;      // 实际调用 d1.operator<<(cout);
}int main()
{TestDate5();return 0;
}

写到这里发现报错了:日期类 流向 控制台

报错原因:对于二元运算符,左操作数对应第一个参数,右操作数对应第二个参数,此处对不上。

虽然是双目对双目,但是有一个是成员函数,有一个是隐含的this,this把第一个位置占了,所以左操作数必须是日期类,右操作数必须是out。

--------------------------------------------------------------------------------------------------------------------------------

修正:(改成控制台流向日期类)

void TestDate5()
{Date d1, d2;// 两种等价写法,都是调用成员函数 operator<<(ostream&)d1 << cout;              // 语法倒装,实际含义:d1.operator<<(cout)d1.operator<<(cout);     // 显式写成成员函数调用
}

此时可以成功匹配,也就是对于void Date::函数来说,双目的第一个参数是this指针(指向日期类),第二个是out。这里的 out 就是 成员函数 operator<< 的形参名,类型为 std::ostream&,表示“往哪里输出”,它对应调用时传进来的实参。

------------------------------------------------------------------------------------------------------------------------------

2)Date::operator<<(ostream& out)作为全局函数:

此时可以写成日期类 流向 控制台。

//不是成员函数,去掉Date::
//小问题,访问不了私有
void operator<<(ostream& out, const Date& d)    
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}//解决方案1:
{
...//private: 放成公有
int year;
int month;
int day;
}
void TestDate5()
{Date d1, d2;//cin >> d1 >> d2;//cout << d1 << d2;cout << d1;operator<<(cout, d1);     //改成全局的才行//T//倒反天罡//d1 << cout;//d1.operator<<(cout);
}

http://www.dtcms.com/a/466862.html

相关文章:

  • wordpress 商品站网站建设 猴王网络
  • 整站seo优化一般多少钱仿it资讯类网站源码
  • 如何建设一个静态网站宝塔怎么做网站的301跳转
  • 做静态网站有什么建议佛山家居网站全网营销
  • 【武大图书馆事件全过程】免费分享
  • SVN 抓取状态
  • Shell 脚本编程全解析:从入门到企业级实战
  • 嘉兴做网站优化杭州小周seo
  • 把网站做成app大冶市建设局网站
  • 吉林分销网站建设视频转文字网页
  • 厦门响应式网站网页做推广
  • 《中国个人信息保护法》解读与实践案例分析
  • 解除网站开发合同 首付款是否退花都区网站建设
  • SQL 注入详解:从原理到实战
  • 校园网站建设情况抽奖网站做的下去吗
  • 5.数据分析Matplotlib(数据可视化)
  • 西双版纳网站制作公司网站集约化建设题目
  • hot100的解析
  • 企业网站建设上机考试微信推广引流方法
  • 【LangChain】P19 LangChain Memory(一):让 AI 拥有“记忆力“的秘密
  • 揭阳网站制作案例宝安中心医院上班时间
  • 吴江开发区建设局网站如何建立网站站点
  • 娱乐公司网站模板西安市网站搭建
  • 做网站运用的软件郑州百姓网免费发布信息网
  • Ansible安装及模块
  • 揭阳网站建设公司全民建网站
  • 哪些网站可以做调查赚钱wordpress服务器镜像
  • AI + 区块链开发实战:3 大技术方向 + 5 个落地案例,解锁去中心化网络效能密码
  • 安阳网站建设方案自己做社交网站吗
  • Linux之curl常用参数介绍