一.運算符重載簡介
1.運算符重載實質
(1) 對已有的運算符賦予多重含義
(2) 必要性:C++預定義的運算符運算對象只能是基本數據類型,而不適用於用戶自定義類型(如 類)
(3) 實現機制:
- 將指定的運算符表達式轉化爲對運算符函數的調用,運算對象轉化運算符函數的實參。
- 編譯系統對重載運算符的選擇,遵循函數重載的選擇原則。
2.規則和限制
(1) 可以重載的運算符:
上述運算符中,[ ] 是下標運算符,()是函數調用運算符,++和 – 是自增自減運算符包括前置後置形式。
另外,有4個運算符不能重載,即 長度運算符 sizeof、條件運算符 ?:、成員選擇符== . == 和域解析運算符== : : == 。
(2) 其他規則
- 不改變原運算符的優先級和結合性。
- 不能改變操作數個數。
- 經重載的運算符,其操作數中至少應該有一個是自定義類型。
二.運算符的重載形式
1.重載爲類成員函數
聲明形式:
函數類型 operator 運算符(形參)
{
函數體;
}
重載爲友元函數時,參數個數=原操作數個數-1 (後置++、–除外)。
(1) 雙目運算符
如果重載運算符B 爲類成員函數,使之能實現表示式oprd1 B oprd2, 其中oprd1位 A類對象,則 B 可被重載爲 A 類的成員函數,形參類型是 oprd2 所屬類型。經重載過,表達式 oprd1 B oprd2 相當於oprd1.operator B(oprd2)
舉例說明:
重載 + 、+=,實現複數類complex 對象想相加。
#include<iostream>
using namespace std;
class complex
{
public:
complex(double real = 0.0, double image = 0.0)
{ this->real = real;this->image = image;}
complex operator + (complex &c1); // 重載 + 爲成員函數
void operator += (complex &c1); //重載 +=
int showComplex(); //輸出複數
private:
double real;
double image;
};
complex complex::operator + (complex &c1) //重載 + 爲成員函數的實現
{
/*complex c; //實現1:創建一個局部變量
c.real = c1.real + real;
c.image = c1.image + image;
return c;
*/
return complex(c1.real + real, c1.image + image); //實現2:創建臨時變量,直接一句代碼返回結果
}
void complex::operator+=(complex &c1) //重載 +=
{
real += c1.real;
image += c1.image;
}
int complex::showComplex()
{
cout << real;
if (image > 0)
cout << "+";
if (image != 0)
cout << image << "i" << endl;
return 0;
}
int main()
{
complex c1(1, 2), c2(-3, 4), c3;
cout << "c1=";c1.showComplex();
cout << "c2=";c2.showComplex();
c3 = c1 + c2; //重載+ 的使用,兩邊都爲complex對象
cout << "c3=c1+c2=";c3.showComplex();
c2 += c1;//重載+= 的使用,兩邊都爲complex對象
cout << "c2+=c1結果: ";c2.showComplex();
return 0;
}
(2) 前置單目運算符
如果要重載 U 爲類成員函數,使之能夠實現表達式 U oprd,其中 oprd 爲A類對象,則 U 可被重載爲 A 類的成員函數,無形參。經重載後,表達式 U oprd 相當於 oprd.operator U()
(3) 後置單目運算符 ++和–
複習一下++ 、–
示例 | 解釋 |
---|---|
++i | i自增1後再參與運算;i的值加1,++i的值也加1 |
i++ | i參與運算後,i的值再加1;i的值加1,i++的值不變 |
如果要重載 ++或–爲類成員函數,使之能夠實現表達式 oprd++ 或 oprd-- ,其中 oprd 爲A類對象,則 ++或-- 可被重載爲 A 類的成員函數,且具有一個 int 類型形參。經重載後,表達式 oprd++ 相當於oprd.operator ++(0)
舉例說明(1):
++ 實現Point類的座標自增
#include<iostream>
using namespace std;
class Point
{
private:
int x, y;
public:
Point(int x, int y)
{
this->x = x;
this->y = y;
}
Point() {}
Point & operator++();//重載前置單目運算符++爲成員函數 ++i i加1,i++整體值加1
Point operator++(int);//重載後置單目運算符++成員函數 i++ 只有i加1,i++值不變
void showPoint();
};
Point & Point::operator++ () //++前置 原來的點變,x,y變
{
++x;
++y;
return *this;
}
Point Point::operator++(int) //後置++ 原來的點不變,x,y加1
{
Point old = (*this); //將舊對象放在新對象裏,末尾返回舊對象
x++;
y++;
return old;
}
void Point::showPoint() {
cout << "(" << x << "," << y << ")" << endl;
}
int main() {
Point p1(1, 2), p2(3, 4), p3, p4;
p3 = ++p1; //++前置
p3.showPoint(); //(2,3)
p4 = p2++; //後置++
p4.showPoint(); //(3,4)
return 0;
}
舉例說明(2):
++ 實現時間的自增
#include<iostream>
using namespace std;
class Clock {
private:
int Hour, Minute, Second;
public:
Clock(int NewH = 0, int NewM = 0, int NewS = 0);
void ShowTime();
Clock operator ++();// 前置單目運算符重載
Clock operator++(int);//後置單目運算符重載
};
Clock::Clock(int NewH, int NewM, int NewS) {
Hour = NewH;
Minute = NewM;
Second = NewS;
}
Clock Clock::operator++() // 前置單目運算符重載
{
Second++;
if (Second >= 60)
{
Second = Second - 60;
Minute++;
if (Minute >= 60)
{
Minute = Minute - 60;
Hour++;
Hour = Hour % 24;
}
}
cout << "++Clock:";
return *this;
}
Clock Clock::operator++(int) // 後置單目運算符重載
{
Clock old = *this;
Second++;
if (Second >= 60)
{
Second = Second - 60;
Minute++;
if (Minute >= 60)
{
Minute = Minute - 60;
Hour++;
Hour = Hour % 24;
}
}
cout << "Clock++:";
return old;
}
void Clock::ShowTime()
{
cout << Hour << ":" << Minute << ":" << Second << endl;
}
int main() {
Clock myclock(23, 59, 59);
cout << "First clock:";
myclock.ShowTime();
(++myclock).ShowTime();
(myclock++).ShowTime();
return 0;
}
2.重載爲友元函數
聲明形式:
friend 函數類型 operator 運算符(形參)
{
函數體;
}
重載爲友元函數時 , 參數個數=原操作數個數,且至少應該有一個自定義類型的形參。
(1) 運算符友元函數的設計
- 如果需要重載一個運算符,使之能夠用於操作某類對象的私有成員,可以此將運算符重載爲該類的友元函數。
- 函數的形參 代表 依自左至右次序排列的各操作數。
- 後置單目運算符 ++和–的重載函數,形參列表中要增加一個int,但不必寫形參名。
雙目運算符 B 重載後,表達式:oprd1 B oprd2 等同於:operator B(oprd1,oprd2)
前置單目運算符 B重載後,表達式:B oprd 等同於:operator B(oprd)
後置單目運算符 ++和–重載後,表達式:oprd B 等同於:operator B(oprd,0)
舉例說明(1):
+、-、=、+=重載爲友元函數 ,以complex類舉例
#include<iostream>
using namespace std;
class complex //複數類聲明
{
public:
complex(double real = 0.0, double image = 0.0) { this->real = real; this->image = image; } //構造函數
friend complex operator + (complex c1, complex c2); //運算符+ 重載爲友元函數
friend complex operator - (complex c1, complex c2); //運算符- 重載爲友元函數
friend bool operator==(const complex &c1, const complex &c2);
friend complex operator += (complex &c1,complex &c2); //運算符+= 重載爲友元函數
void showComplex(); //顯示覆數的值
private:
double real;
double image;
};
complex operator+(complex c1, complex c2)
{
return complex(c2.real + c1.real, c2.image + c1.image);
}
complex operator-(complex c1, complex c2)
{
return complex(c1.real - c2.real, c1.image - c2.image);
}
bool operator==(const complex &c1, const complex &c2) {
if (c1.real == c2.real && c1.image == c2.image) {
return true;
} else {
return false;
}
}
complex operator+=(complex &c1, complex &c2)
{
c1.real += c2.real;
c1.image += c2.image;
}
void complex::showComplex()
{
cout << real;
if (image > 0)
cout << "+";
if (image != 0)
cout << image << "i" << endl;
}
int main()
{
complex c1(1, 2), c2(-3, 4), c3, c4;
cout << "c1=";c1.showComplex();
cout << "c2=";c2.showComplex();
c3 = c1 + c2;
cout << "c3=c1+c2=";c3.showComplex();
c4 = c1 - c3;
cout << "c4=c1-c3=";c4.showComplex();
if(c4==c1){
cout << "c4==c1"<<endl;
}
return 0;
}
舉例說明(2):
c1+c2, c1+i, i+c1
#include <iostream>
using namespace std;
class complex
{
public:
complex(double real = 0.0, double image = 0.0)
{this->real = real;this->image = image;}
void show();
friend complex operator + (complex&c1, complex&c2);
friend complex operator + (complex&c1, int c2);
friend complex operator + (int c1, complex&c2);
private:
double real;
double image;
};
complex operator + (complex&c1, complex&c2)
{
complex c;
c.real = c1.real + c2.real;
c.image = c1.image + c2.image;
return c;
}
complex operator + (complex&c1, int c2)
{
complex c;
c.real = c1.real + c2;
c.image = c1.image;
return c;
}
complex operator + (int c1, complex&c2)
{
complex c;
c.real = c2.real + c1;
c.image = c2.image;
return c;
}
void complex::show()
{
cout << "(" << real << " + " << image << "i" << ")"<<endl;
}
int main()
{
complex c1(1, 2),c2(3,4),c3,c4,c5;
int i = 2;
cout << "i=" << i << endl;
cout << "c1=";c1.show();
cout << "c2=";c2.show();
c3 = c1 + c2;
cout << "c3=c1+c2=";c3.show();
c4 = c1+i;
cout << "c4=c1+i=";c4.show();
c5 = i + c1;
cout << "c5=i+c1=";c5.show();
return 0;
}
3.特殊介紹
(1) 下標運算符[ ] 重載爲成員函數
該重載函數在類中的聲明格式:
返回值類型 & operator[](參數);
const 返回值類型 & operator[](參數) const;
使用第一種聲明方式,[ ]不僅可以訪問元素,還可以修改元素;
使用第二種聲明方式,[ ]只能訪問而不能修改元素;
在實際開發中,我們應該同時提供以上兩種形式,這樣做是爲了適應 const 對象,因爲通過 const 對象只能調用 const 成員函數,如果不提供第二種形式,那麼將無法訪問 const 對象的任何元素;
#include<iostream>
#include<cstring>
using namespace std;
class MyString {
public:
MyString();//默認構造函數
MyString(const char*const); //構造函數
MyString(const MyString&);//複製構造函數
~MyString();//析構函數
char & operator[](int n); //成員函數重載[],該形式可修改可訪問元素
char operator[](int n)const;//常成員函數重載[],用於const對象調用
int getLen()const { return length;}
const char *getMyString()const {return myString;}
private:
char *myString;
int length;
};
MyString::MyString() { //默認構造函數
myString = new char[1];
myString[0] = '\0';
length = 0;
}
MyString::MyString(const char *const str) { //構造函數
length = strlen(str);
myString = new char[length + 1];
for (int i = 0;i < length;i++)
myString[i] = str[i];
myString[length] = '\0';
}
MyString::MyString(const MyString &str) { //複製構造函數
length = str.getLen();
myString = new char[length + 1];
for (int i = 0;i < length;i++)
myString[i] = str[i];
myString[length] = '\0';
}
MyString::~MyString() { //析構函數
delete[]myString;
length = 0;
}
char & MyString::operator [](int n) { //下標運算符[]重載
if (n > length | n < 0)
cout << "數組下標越界!" << endl;
else
return myString[n];
}
char MyString::operator [](int n)const
{
if (n > length | n < 0)
cout << "數組下標越界!" << endl;
else
return myString[n];
}
int main() {
MyString str1("xiaobencong zhen shuai!");
cout << "str1: " << str1.getMyString() << endl;
cout << "str1[4]: " << str1[4] << endl;
cout << "str1[-1]: " << str1[-1] << endl;
cout << "str1[99]:" << str1[999] << endl;
return 0;
}
(2) 關於 什麼時候用友元函數和成員函數,大家可以閱讀這篇文章:
C++ 運算符重載
歡迎關注微信公衆號:學編程的金融客,作者:小笨聰