目錄
1.流提取運算符>>的重載
知識回顧
重載方法
operator<<格式
operator>>格式
使用cin對日期類對象寫入數據
如果想指定格式輸入
方法1:getchar()
方法2:使用臨時變量接收字符
完善operator>>代碼(修bug)
2.類中的權限問題(const成員)
問題
分析
建議
解釋:成員函數后面加const以后普通對象和const對象都可以調用
3.const練習
承接CD21.【C++ Dev】類和對象(12) 流插入運算符的重載文章
1.流提取運算符>>的重載
知識回顧
流提取運算符的基礎知識參見CC2.【C++ Cont】初認識cout,cin和endl文章
重載方法
和CD21.【C++ Dev】類和對象(12) 流插入運算符的重載文章的operator<<重載格式一樣
operator<<格式
ostream& operator<<(ostream& out, const Date& d)
operator>>格式
(來自https://legacy.cplusplus.com/reference/istream/istream/operator%3E%3E/)
查資料可知,返回值應該為istream&,第一個參數的也為istream&
istream& operator>>(istream& in, const Date& d)
{//......return in;
}
?注意:兩個參數都不能使用const修飾
1.cin是一個全局對象,輸入實際上是通過的cin這個對象,輸入的東西需要cin去接受,如果加了const,cin就無法修改
2.由于需要對d的成員變量寫入數據,不能加const
在類里面寫operator>>友元函數聲明,便于訪問私有成員變量:
class Date
{friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);
public://......
private:int _year;int _month;int _day;
};
使用cin對日期類對象寫入數據
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
測試代碼:
#include "Date.h"
int main()
{Date d1(0, 0, 0);cin >> d1;cout << d1;return 0;
}
運行結果:
如果想指定格式輸入
方法1:getchar()
例如輸入2025/3/31.可以這樣修改代碼
istream& operator>>(istream& in, Date& d)
{in >> d._year;getchar();in >> d._month;getchar();in>> d._day;return in;
}
運行結果:
方法2:使用臨時變量接收字符
該臨時變量僅接收字符,并無實際作用,所以起名為unused
istream& operator>>(istream& in, Date& d)
{char unused;in >> d._year >> unused >> d._month >> unused >> d._day;return in;
}
運行結果:
完善operator>>代碼(修bug)
代碼要有魯棒性,因此需要對非法日期做處理
1.月必須介于1~12之間
2.天數必須合法
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;if (d._month < 1 || d._month>12){cout << "非法日期" << endl;exit(EXIT_FAILURE);//錯誤退出}if (d._day <= 0 || d._day > GetMonthDay(d._year,d._day)){cout << "非法日期" << endl;exit(EXIT_FAILURE);//錯誤退出}return in;
}
(也可以將exit(EXIT_FAILURE)改成assert(false),因為里面為false,為無條件斷言)?
其他寫法:將判斷條件寫入assert中:
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;assert(!(d._month < 1 || d._month>12));assert(!(d._day <= 0 || d._day > GetMonthDay(d._year, d._month)));return in;
}
這樣斷言的好處:能具體告訴日期的哪一個部分是非法的,例如:
1.月份是非法的
2.天數是非法的
2025年不是閏年,2月最多28天
運行結果:
發現退出代碼不為0,這和頭文件中EXIT_FAILURE定義的值有關
(VS2022的stdlib.h中有定義)
2.類中的權限問題(const成員)
使用const繞不開權限的放大縮小平移的問題,看下面的例子:
Date中的Print函數:
void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}
測試代碼:
#include "Date.h"
int main()
{const Date d1(2025, 3, 31);d1.Print();return 0;
}
報錯:
分析:
Print()中隱藏的參數是this,雖然this指針的類型為const Date*,但是?const Date*中const只表示this指針本身不能修改,并沒有表示this指向對象的成員變量不能修改
?實參this表示this指向的成員變量不可以修改(const Date d1(2025, 3, 31);),但Print()接收的this表示this指向的成員變量可以修改(void Date::Print()),導致權限的放大
解決方法:在Print函數后面加上const即可,const修飾*this(注意星號),這樣就為權限的平移
void Date::Print() const//const修飾*this,this的類型為const Date* const
{cout << _year << "/" << _month << "/" << _day << endl;
}
(注加上的const不能寫在Print()的括號里面,隱式參數this類型不能在括號里面修改,這是語法規定)
運行結果:
問題
下面是權限的平移放大還是縮小?是否正常運行?
void Date::Print() const
{cout << _year << "/" << _month << "/" << _day << endl;
}//......#include "Date.h"
int main()
{Date d1(2025, 3, 31);d1.Print();return 0;
}
分析
Date d1(2025, 3, 31);表示this指向的對象可以修改,void Date::Print() const表示this指向的對象不可以修改,從可以修改到不可以修改為權限的縮小,正常運行
建議
★如果對象的成員變量不改變(注意前提),最好在成員函數的后面加上const,成員函數后面加const以后普通對象和const對象都可以調用
例如日期+天數,日期類對象不改變,則在operator+函數后加上const
提醒:非成員函數上不允許修飾符const
(operator<<不是成員函數,沒有使用Date::)
但也不能不看實際情況就加const
例如operator-復用了operator-=的代碼,加了const就不能對*this修改
解釋:成員函數后面加const以后普通對象和const對象都可以調用
測試代碼:
#include "Date.h"
int main()
{const Date d1(2025, 3, 31);Date d2(2025, 4, 1);d1 < d2;d2 < d1;return 0;
}
分別對加了const和沒有加const的operator<測試
先分析沒有加const的:
bool Date::operator< (const Date& d2)
{if (_year < d2._year)return true;else if (_year == d2._year && _month < d2._month)return true;else if (_year == d2._year && _month == d2._month && _day < d2._day)return true;return false;
}
讀測試代碼可知:
d1<d2的執行會有問題,由d1的定義可知:d1的成員對象不能修改,而bool Date::operator< (const Date& d2)第一個參數為this,與d1的地址對應,導致權限的放大,會報錯
d2<d1執行沒有問題,是權限的縮小,沒有問題
再分析加了const的:
d1<d2:權限的平移,沒有問題
d2<d1:權限的縮小,沒有問題
3.const練習
1. const對象可以調用非const成員函數嗎?
2. 非const對象可以調用const成員函數嗎?
3. const成員函數內可以調用其它的非const成員函數嗎?
4. 非const成員函數內可以調用其它的const成員函數嗎?
答案見下篇