=========================================================================
個人主頁點擊直達(dá):小白不是程序媛
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 :要復(fù)合連續(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),編譯器會生成一個默認(rèn)的。此時用戶再在類外自己實現(xiàn)
一個全局的賦值運算符重載,就和編譯器在類中生成的默認(rèn)賦值運算符重載沖突了,故賦值
運算符重載只能是類的成員函數(shù)。用戶沒有顯式實現(xiàn)時,編譯器會生成一個默認(rè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-1
return 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取地址操作符重載
這兩個默認(rèn)成員函數(shù)一般不用重新定義 ,編譯器默認(rèn)會生成。
class Date
{
public:
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
這兩個運算符一般不需要重載,使用編譯器生成的默認(rèn)取地址的重載即可,只有特殊情況,才需
要重載,比如想讓別人獲取到指定的內(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;
}
這里我們使用操作符重載,完成了一個簡單的日期計算器,當(dāng)然這其中還有很多沒有完善的地方。像我們構(gòu)造一些非法的數(shù)據(jù)作為日期等等一些小問題,我就留給大家了。
C++類和對象(中)的六個成員函數(shù)就講完了,大家可以結(jié)合上篇文章細(xì)細(xì)閱讀,慢慢探索C++這六個成員函數(shù)的奧秘?,總結(jié)收獲出一些自己的東西。也希望大家留言指出我文章中出現(xiàn)的內(nèi)容,同時也感謝各位看官的三連支持,你們的支持就是我更新的動力!??!?文章來源:http://www.zghlxwxcb.cn/news/detail-738757.html
下篇預(yù)告:類和對象(下)文章來源地址http://www.zghlxwxcb.cn/news/detail-738757.html
到了這里,關(guān)于【C++初階】類和對象——操作符重載&&const成員函數(shù)&&取地址重載&&日期類的實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!