C++基礎 學習筆記五:重載之運算符重載 什麼是運算符重載 用同一個運算符完成不同的功能即同一個運算符可以有不同的功能的方法叫做運算符重載。運算符重載是靜態多態性的體現。 運算符重載的規則 1. 重載公式 返回值類型 operator 運算符名稱 (形參表列){} 2. 能夠重載的運算符 ` ` ` ...
C++基礎 學習筆記五:重載之運算符重載
什麼是運算符重載
用同一個運算符完成不同的功能即同一個運算符可以有不同的功能的方法叫做運算符重載。運算符重載是靜態多態性的體現。
運算符重載的規則
-
重載公式
返回值類型 operator 運算符名稱 (形參表列){}
-
能夠重載的運算符
+
-
*
/
%
^
&
|
~
!
=
<
>
+=
-=
*=
/=
%=
^=
&=
|=
<<
>>
<<=
>>=
==
!=
<=
>=
&&
||
++
--
,
->*
->
()
[]
new
new[]
delete
delete[]
-
不能重載的運算符
sizeof
、: ?
、.
、::
-
重載不能改變運算符的優先順序和結合性
-
重載不會改變運算符的用法
-
運算符重載函數不能有預設的參數
-
重載後的運算符必須至少有一個操作數是用戶自定義的類型,以此來防止為標準類型重載運算符。
-
特殊的運算符
->
、[ ]
、( )
、=
只能以成員函數的形式重載
運算符重載的實現原理
以運算符作為名稱的函數稱之為運算符函數。這種重載稱為運算符重載。
具體實現(以運算符+
-
為例)
1. 在全局範圍內重載運算符
Complex operator+(const Complex &leftArg, const Complex &rightArg)
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
Complex sum = leftArg + rightArg;
第五行調用函數operator+,並且將leftArg
、leftArg
作為符號函數的參數,返回值賦值給sum
,等同於sum = operator+(leftArg,rightArg);
。
2.在類中重載運算符
class Complex
{
public:
Complex operator-(const Complex & arg)
{
return Complex(this.real - arg.real, this.imag - arg.imag);
}
};
Complex diff = leftArg - rightArg;
第九行調用函數operator-,並且將leftArg
作為符號函數的參數,返回值賦值給diff
,等同於diff = leftArg.operator-(rightArg);
。
運算符重載的使用例子
#include<iostream>
#include<string>
using namespace std;
enum complePart
{
real = 0,
imag
};
class Complex
{
public:
int real;
int imag;
public:
Complex() : real(0),imag(0){}
Complex(int r, int i) : real(r),imag(i){}
Complex operator-(const Complex & arg)// +,-,*,/ 這四個運算符重載方法一樣
{
return Complex(this->real - arg.real, imag - arg.imag);
}
friend Complex operator*(const Complex &leftArg, const Complex &rightArg);//友元函數
bool operator==(const Complex &arg)// ==,!= 這兩個個運算符重載方法一樣
{
if(this->real == arg.real && this->imag == arg.imag)
return true;
else
return false;
}
Complex& operator+=(const Complex &arg)// +=,-=,*=,/= 這四個運算符重載方法一樣
{
this->real += arg.real;
this->imag += arg.imag;
return *this;
}
friend istream& operator>>(istream &input, Complex &complex);
friend ostream& operator<<(ostream &output, Complex &complex);
Complex& operator++()// ++i,--i 這兩個個運算符重載方法一樣
{
++this->real;
++this->imag;
return *this;
}
Complex operator++(int i)// i++,i-- 這兩個個運算符重載方法一樣
{
Complex tempComplex = *this;
++this->real;
++this->imag;
return tempComplex;
}
void* operator new(size_t size)
{
cout << "call function void* operator new(size_t size)" << endl;
void* pointer = malloc(size);
return pointer;
}
void operator delete(void* pointer)
{
cout << "call function void operator delete(void* pointer)" << endl;
free(pointer);
}
void* operator new[](size_t size)
{
cout << "call function void* operator new[](size_t size)" << endl;
void* pointer = malloc(size);
return pointer;
}
void operator delete[](void* pointer)
{
cout << "call function void operator delete[](void* pointer)" << endl;
free(pointer);
}
void* operator new(size_t size,Complex* complex,int step)//placement new
{
cout << "call function void* operator new(size_t size,Complex* complex,int step)" << endl;
return complex + step;
}
operator int()
{
return this->real;
}//c->operator int()
int& operator [](int i)
{
int errorValue = 0;
if(i == 0)
return this->real;
else//為了演示不要在意
return this->imag;
}
const int& operator[](int i) const
{
cout << "call function const int& operator[](int i) const" << endl;
if(i == 0)
return this->real;
else//為了演示不要在意
return this->imag;
}
};
Complex operator+(const Complex &leftArg, const Complex &rightArg)//全局重載
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
istream& operator>>(istream &input, Complex &complex)
{
input >> complex.real >> complex.imag;
return input;
}
ostream& operator<<(ostream &output, Complex &complex)
{
output << complex.real << " " << complex.imag << " ";
return output;
}
Complex operator*(const Complex &leftArg, const Complex &rightArg)
{
return Complex((leftArg.real * rightArg.real) - (leftArg.imag * rightArg.imag),
(leftArg.imag * rightArg.real) - (leftArg.real * rightArg.imag));
}
int main()
{
Complex leftArg(2,2);
Complex rightArg;
cin >> rightArg;//輸入3,3
Complex result = leftArg + rightArg;
cout << result << endl;
result = leftArg - rightArg;
cout << result << endl;
result = leftArg * rightArg;
cout << result << endl;
string str = (leftArg == rightArg)?"true":"false";
cout << str << endl;
result += leftArg;
cout << result << endl;
cout << ++result << endl;
Complex resulttttt = result++;
cout << resulttttt << endl;
cout << result << endl;
Complex* pointer = new Complex(1,1);
cout << *pointer << endl;
delete pointer;
Complex* pointerArray = new Complex[10];
cout << pointerArray[2] << endl;
new(pointerArray, 2)Complex(123,321);//placement new
cout << pointerArray[2] << endl;
cout << (int)pointerArray[2] << endl;
cout << pointerArray[2][complePart::real] << endl;
cout << pointerArray[2][complePart::imag] << endl;
delete[] pointerArray;
const Complex c_result(111,222);
cout << c_result[complePart::imag] << endl;
return 0;
}
/* 運行結果為:
3 3
5 5
-1 -1
0 0
false
2 2
3 3
3 3
4 4
call function void* operator new(size_t size)
1 1
call function void operator delete(void* pointer)
call function void* operator new[](size_t size)
0 0
call function void* operator new(size_t size,Complex* complex,int step)
123 321
123
123
321
call function void operator delete[](void* pointer)
call function const int& operator[](int i) const
222
--------------------------------
Process exited after 3.063 seconds with return value 0
請按任意鍵繼續. . .
*/
代碼分析
1.雙目運算符
+
、-
、*
、/
、%
這五個運算符均為雙目運算符,重載方法相同。重載例子詳見第20、24、102、116行,其中第102行的+
重載函數為全局重載,測試詳見第127、129、131行。
2.關係運算符
==
、!=
、<
、>
、<=
、>=
這六個運算符均為關係運算符,重載方法相同。重載例子詳見第25行,測試詳見第133行。
3.自增自減運算符
++
、--
這兩個運算符均為自增自減運算符,由於運算符的特殊性,運算符又分為前置和後置形式。重載方法兩種形式不同,但是相同形式的重載方法相同。重載例子詳見第40、46行,測試詳見第137、138行。
4.空間申請與釋放運算符
new
、delete
、new[]
、delete[]
這四個運算符均為空間申請與釋放運算符,重載方法相似。重載例子詳見第53、59、64、70行,測試詳見第141、143、144、151行。在重載空間申請運算符時除new
、new[]
這兩種方式外還有一種方式叫做placement new
。重載例子詳見第75行,測試詳見第146行。
placement new
通常new
操作分兩步:
- 分配記憶體。
- 若為類則調用類的構造函數創建對象。
但是若已分配好記憶體如:Complex* pointerArray = new Complex[10];
,若要在pointerArray[2]
分配的記憶體上創建對象則需要用placement new
來完成該操作。操作如下:new(pointerArray, 2)Complex(123,321);
,完成該操作後pointerArray[2]
中的複數對象將會變為123+321i
。
5.輸入和輸出運算符
>>
、<<
這兩個運算符均為輸入和輸出運算符,重載方法相似。可以將輸出運算符<<
和輸入運算符>>
看作是C++對左移運算符<<
和右移運算符>>
分別進行了重載,但只能輸出輸入標準類型。重載例子詳見第38、39行,測試詳見第126、128行。
6.其它運算符
-
(數據類型)
運算符(數據類型)
是強制類型轉換運算符,可以將對象轉換為相應的類型。 -
[]
運算符[]
是下標運算符,可以將對象轉換為類似數組,可以通過下標操縱對象。
重載運算符的形式
1.以成員函數重載運算符
成員函數重載只允許右參數的隱式轉換,一般單目運算符以成員函數重載。只能重載為成員函數的運算符:=
、()
、[]
、->
等。
2.以全局函數(友元函數)重載運算符
友元函數重載能夠接受左參數和右參數的隱式轉換,友員函數重載運算符常用於運算符的左右操作數類型不同的情況。一般雙目運算符以友元函數重載。只能重載為友元函數的運算符:<<
、>>
等。