有名網(wǎng)站建設(shè)公司百度網(wǎng)盤pc端網(wǎng)頁版
=========================================================================
個人主頁點擊直達:小白不是程序媛
C++系列專欄:C++頭疼記
=========================================================================
目錄?
前言:
運算符重載
運算符重載?
賦值運算符重載
前置++和后置++重載
const成員
取地址及const取地址操作符重載
使用函數(shù)操作符重載完成日期類的實現(xiàn)
前言:
上篇文章介紹了在C++的類六個成員函數(shù)中的三個,分別是構(gòu)造函數(shù)、析構(gòu)函數(shù)、拷貝構(gòu)造函數(shù),不知道大家有沒有所收獲,今天我們帶來的是剩下的三個函數(shù),以及結(jié)合這六個函數(shù)完成一個完整的日期類的實現(xiàn),讓我們開始今天的征程吧!
運算符重載
在C++中有很多的運算符,包括 +、- 、* 、/、等等,一個兩兩結(jié)合的操作符++、--、+=,>=、==等等。
int main()
{int i = 0;cout << ++i << endl;cout << --i << endl;i = 2;cout << i << endl;return 0;
}
對于內(nèi)置類型來說我們可以直接使用,但是對于我們自己定義的自定義類型呢?該如何使用呢?
-
運算符重載?
C++為了增強代碼的可讀性引入了運算符重載,運算符重載是具有特殊函數(shù)名的函數(shù),也具有其
返回值類型,函數(shù)名字以及參數(shù)列表,其返回值類型與參數(shù)列表與普通的函數(shù)類似。
函數(shù)名字為:關(guān)鍵字operator后面接需要重載的運算符符號。
函數(shù)原型:返回值類型?operator操作符(參數(shù)列表)?
注意:
- 不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@
- 重載操作符必須有一個類類型參數(shù)
- 用于內(nèi)置類型的運算符,其含義不能改變,例如:內(nèi)置的整型+,不 能改變其含義
- 作為類成員函數(shù)重載時,其形參看起來比操作數(shù)數(shù)目少1,因為成員函數(shù)的第一個參數(shù)為隱藏的this
- .*? ::? sizeof? ?:? . 注意以上5個運算符不能重載。這個經(jīng)常在筆試選擇題中出現(xiàn)。
示例:==運算符重載
class Date
{
public:Date(int year = 1, int month = 1,int day=1){_year = year;_month = month;_day = day;}bool operator==(const Date& y){return _year == y._year && _month == y._month && _day == y._day;}
private :int _year;int _month;int _day;
};
-
賦值運算符重載
賦值運算符重載格式
參數(shù)類型:const T&,傳遞引用可以提高傳參效率
返回值類型:T&,返回引用可以提高返回的效率,有返回值目的是為了支持連續(xù)賦值檢測是否自己給自己賦值
返回*this :要復合連續(xù)賦值的含義
class Date
{
public:Date(int year = 1, int month = 1,int day=1){_year = year;_month = month;_day = day;}Date& operator=(const Date& d){this->_year = d._year;this->_month = d._month;this->_day = d._day;return *this;}
private :int _year;int _month;int _day;
};
賦值運算符只能重載成類的成員函數(shù)不能重載成全局函數(shù)
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};
// 賦值運算符重載成全局函數(shù),注意重載成全局函數(shù)時沒有this指針了,需要給兩個參數(shù)
Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}
?原因:賦值運算符如果不顯式實現(xiàn),編譯器會生成一個默認的。此時用戶再在類外自己實現(xiàn)
一個全局的賦值運算符重載,就和編譯器在類中生成的默認賦值運算符重載沖突了,故賦值
運算符重載只能是類的成員函數(shù)。用戶沒有顯式實現(xiàn)時,編譯器會生成一個默認賦值運算符重載,以值的方式逐字節(jié)拷貝。
注意:內(nèi)置類型成員變量是直接賦值的,而自定義類型成員變量需要調(diào)用對應(yīng)類的賦值運算符
重載完成賦值。
class Date
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}Date(int year = 1, int month = 1,int day=1){_year = year;_month = month;_day = day;}
private :int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();Date d2 = d1;d2.Print();return 0;
}
這里我們沒有寫賦值重載函數(shù),編譯器會自動生成一個完成操作,和拷貝構(gòu)造函數(shù)優(yōu)點類似。
注意:如果類中未涉及到資源管理,賦值運算符是否實現(xiàn)都可以;一旦涉及到資源管理則必
須要實現(xiàn)。
-
前置++和后置++重載
class Date
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}Date(int year = 1, int month = 1,int day=1){_year = year;_month = month;_day = day;}// 前置++:返回+1之后的結(jié)果// 注意:this指向的對象函數(shù)結(jié)束后不會銷毀,故以引用方式返回提高效率Date& operator++(){*this += 1;return *this;}// 后置++:// 前置++和后置++都是一元運算符,為了讓前置++與后置++形成能正確重載// C++規(guī)定:后置++重載時多增加一個int類型的參數(shù),但調(diào)用函數(shù)時該參數(shù)不用傳遞,編譯器自動傳遞// 注意:后置++是先使用后+1,因此需要返回+1之前的舊值,故需在實現(xiàn)時需要先將this保存一份,然后給this + 1// ???而temp是臨時對象,因此只能以值的方式返回,不能返回引用Date operator++(int){Date tmp(*this);*this += 1;return tmp;}
private :int _year;int _month;int _day;
};
int main()
{Date d1;d1++;// 1-1-2++d1;// 1-1-1return 0;
}
const成員
將const修飾的“成員函數(shù)”稱之為const成員函數(shù),const修飾類成員函數(shù),實際修飾該成員函數(shù)
隱含的this指針,表明在該成員函數(shù)中不能對類的任何成員進行修改。
我們來看看下面這段代碼?
class Date
{
public://void Print( Date *this)void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year = 1;int _month = 1;int _day = 1;
};
int main()
{const Date d1;//d1.Print(&d1)//權(quán)限放大d1.Print();return 0;
}
這段代碼在編譯器上是編譯不通過的,說明語法有問題。
因為我們創(chuàng)建了一個const Date *的d1,將d1作為參數(shù)傳給函數(shù)時,函數(shù)的的參數(shù)是一個Date *,兩個參數(shù)不匹配,權(quán)限會放大,所以編譯不通過。
其實函數(shù)的形參就是this指針,那我們?nèi)绾螌his指針修飾為const呢?
只需要在函數(shù)聲明后面加上const 即可將this指針修飾為const。
class Date
{
public://void Print( Date *this)void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year = 1;int _month = 1;int _day = 1;
};
int main()
{const Date d1;//d1.Print(&d1)//權(quán)限放大d1.Print();Date d2;d2.Print();return 0;
}
上面為修飾后的代碼,我們在創(chuàng)建一個普通的Date *,能否在const修飾的this指針函數(shù)中跑起來呢?
答案是可以的,因為權(quán)限可以平移、縮小,不能放大。
那么請思考以下問題:
const對象可以調(diào)用非const成員函數(shù)嗎?
????????不可以,權(quán)限放大。
非const對象可以調(diào)用const成員函數(shù)嗎?? ? ? ? 可以,權(quán)限縮小。
const成員函數(shù)內(nèi)可以調(diào)用其它的非const成員函數(shù)嗎?? ? ? ? 不可以,權(quán)限放大。
非const成員函數(shù)內(nèi)可以調(diào)用其它的const成員函數(shù)嗎??? ? ? ? 可以,權(quán)限縮小。
取地址及const取地址操作符重載
這兩個默認成員函數(shù)一般不用重新定義 ,編譯器默認會生成。
class Date
{
public:Date* operator&(){return this;}const Date* operator&()const{return this;}
private:int _year; // 年int _month; // 月int _day; // 日
};
這兩個運算符一般不需要重載,使用編譯器生成的默認取地址的重載即可,只有特殊情況,才需
要重載,比如想讓別人獲取到指定的內(nèi)容!?
這個函數(shù)基本沒有什么作用,很少用到作為了解即可!
使用函數(shù)操作符重載完成日期類的實現(xiàn)
void Date::Print()
{cout << _year << "-" << _month << "-" << _day << endl;
}
//獲取天數(shù)
int Date::GetMonthDay(int year, int month)
{int monthArr[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))){return 29;}return monthArr[month];
}
//構(gòu)造函數(shù)
Date::Date(int year=1, int month=1, int day=1)
{_year = year;_month = month;_day = day;
}
//拷貝構(gòu)造函數(shù)
Date::Date(const Date& d)
{this->_year = d._year;this->_month = d._month;this->_day = d._day;
}
//賦值運算符重載
Date& Date::operator=(const Date& d)
{this->_year = d._year;this->_month = d._month;this->_day = d._day;return *this;
}
//日期+=天數(shù)
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;
}
//日期+天數(shù)
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return *this;
}
//日期-=天數(shù)
Date& Date::operator-=(int day)
{_day -= day;while (_day <= 0){//月小于0時應(yīng)該先借位--_month;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}
//日期-天數(shù)
Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return *this;
}
//前置++
Date& Date::operator++()
{*this += 1;return *this;
}
//后置++
Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}
//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
//后置--
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}
//>運算符重載
bool Date::operator>(const Date& y)
{if (_year > y._year){return true;}else if (_year == y._year && _month > y._month){return true;}else if (_year == y._year && _month == y._month && _day > y._day){return true;}return false;
}
//==運算符重載
bool Date::operator==(const Date& y)
{return _year == y._year && _month == y._month && _day == y._day;
}
//>=運算符重載
bool Date::operator>=(const Date& y)
{return *this > y || *this == y;
}
//<運算符重載
bool Date::operator<(const Date& y)
{return !(*this >= y);
}
//!=運算符重載
bool Date::operator!=(const Date& y)
{return !(*this == y);
}
//日期-日期 返回天數(shù)
int Date::operator-(const Date& y)
{Date max = *this;Date min = y;if (*this < y){max = y;min = *this;}int n = 0;while (min != max){min++;n++;}return n;
}
這里我們使用操作符重載,完成了一個簡單的日期計算器,當然這其中還有很多沒有完善的地方。像我們構(gòu)造一些非法的數(shù)據(jù)作為日期等等一些小問題,我就留給大家了。
C++類和對象(中)的六個成員函數(shù)就講完了,大家可以結(jié)合上篇文章細細閱讀,慢慢探索C++這六個成員函數(shù)的奧秘?,總結(jié)收獲出一些自己的東西。也希望大家留言指出我文章中出現(xiàn)的內(nèi)容,同時也感謝各位看官的三連支持,你們的支持就是我更新的動力!!!?
下篇預告:類和對象(下)