天天看點

C++運算符重載相關問題0.什麼是運算符重載1. C++運算符重載的原則是什麼?有哪些規則?2. C++能/不能重載的運算符有哪幾個?3. C++運算符重載的形式有哪幾種?4.C++幾種特殊的運算符重載

目錄

0.什麼是運算符重載

C++運算符重載:

1. C++運算符重載的原則是什麼?有哪些規則?

C++運算符重載:

重載原則:

重載規則:

2. C++能/不能重載的運算符有哪幾個?

能重載的運算符有:

不能重載的運算符有:

3. C++運算符重載的形式有哪幾種?

普通函數:

友元函數:

成員函數:

4.C++幾種特殊的運算符重載

0.什麼是運算符重載

運算符重載:對已有的運算符重新進行定義,賦予其另一種功能,以适應不同的資料類型。

引用wikipedia對運算符重載的解釋:

運算符重載

在計算機程式設計中,運算符重載(英語:operator overloading)是多态的一種。這裡,運算符(比如+,=或==)被當作多态函數,他們的行為随着其參數類型的不同而不同。運算符并不一定總是符号。

運算符重載通常隻是一種文法糖。它可以簡單地通過函數調用來模拟:

a + b * c
           
在一個支援運算符重載的語言裡,上面的寫法要比下面的寫法有效而簡練:
add(a, multiply(b, c))
           

(假設運算符* 的優先級高于運算符 +)

當一種語言允許運算符在某種情況下被隐式調用的時候,運算符重載将不隻提供寫法上的友善。例如,Ruby中的

to_s

運算符就是如此,它傳回一個對象的字元串表示。

用途

運算符重載由于使程式員能夠根據運算符類型的不同來決定運算符功能的不同而有多樣用途。C++中

<<

的使用就是一個例子。表達式
a << 1
           
當a是整型變量時将傳回a的兩倍,但是當a是一個輸出流時将向這個流中寫入“1”。因為運算符重載允許程式員改變運算符通常的語義,慎重使用運算符重載通常被認為是一個好習慣。

C++運算符重載:

C++内部定義的資料類型(int , float, …)的資料操作可以用運算符号來表示,其使用形式是表達式;使用者自定義的類型的資料的操作則用函數表示,其使用形式是函數調用。為了使對使用者自定義資料類型的資料的操作與内置的資料類型的資料的操作形式一緻,C++提供了運算符的重載,通過把C++中預定義的運算符重載為類的成員函數或者友元函數,使得對使用者的自定義資料類型的資料—對象的操作形式與C++内部定義的類型的資料一緻。

首先來看一個問題:代碼定義了一個複數類complex,然後用complex定義了2個複數,如何實作這2個複數的加法呢?這個問題的解決就需要用到運算符重載的知識。

//運算符重載的必要性
#include <iostream>
using namespace std;

class complex		//定義複數類 complex
{
private:
	double real, imag;	//private 成員,分别代表實部和虛部

public:
	complex(double r = 0.0, double i = 0.0)	//構造函數,帶預設參數值
	{
		real = r;
		imag = i;
	}

	void disp()		//成員函數,輸出複數
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};

int main()
{
	complex cx1(1.0, 2.0);
	complex cx2(3.0, 4.0);
	complex cxRes = cx1 + cx2;	//錯誤
	
	return 0;
}

           

1. C++運算符重載的原則是什麼?有哪些規則?

C++運算符重載:

p系統本身就提供了很多個重載版本,如:

int operator + (int,int);

double operator + (double,double);
           

重載原則:

  • 1)重載操作符必須具有一個類類型或者是枚舉類型的操作數。
    • –int operator+(int, int);//不能重載
  • 2)重載操作符必須具有一個類類型或者是枚舉類型的操作數。
    • 操作符的優先級、結合性或操作數個數不能改變
  • 3)p不再具備短路求值特性。
    • 重載操作符并不保證操作數的求值順序  &&  ||   
  • 4)不能臆造并重載一個不存在的運算符。
    • 如@, #,$等

重載規則:

  • 1)除了類屬關系運算符 " . " 、成員指針運算符 " .* " 、作用域運算符 " :: " 、sizeof運算符和三目運算符 " ?: " 以外,C ++ 中的所有運算符都可以重載。
  • 2)重載運算符限制在C ++ 語言中已有的運算符範圍内的允許重載的運算符之中,不能建立新的運算符。
  • 3) 運算符重載實質上是函數重載,是以編譯程式對運算符重載的選擇,遵循函數重載的選擇原則。
  • 4 )重載之後的運算符不能改變運算符的優先級和結合性,也不能改變運算符操作數的個數及文法結構。
  • 5 )運算符重載不能改變該運算符用于内部類型對象的含義。它隻能和使用者自定義類型的對象一起使用,或者用于使用者自定義類型的對象和内部類型的對象混合使用時。
  • 6 )運算符重載是針對新類型資料的實際需要對原有運算符進行的适當的改造,重載的功能應當與原有功能相類似,避免沒有目的地使用重載運算符

2. C++能/不能重載的運算符有哪幾個?

能重載的運算符有:

雙目算術運算符 + (加),-(減),*(乘),/(除),% (取模)
關系運算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
邏輯運算符 ||(邏輯或),&&(邏輯與),!(邏輯非)
單目運算符 + (正),-(負),*(指針),&(取位址)
自增自減運算符 ++(自增),--(自減)
位運算符 | (按位或),& (按位與),~(按位取反),^(按位異或),,<< (左移),>>(右移)
指派運算符 =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空間申請與釋放 new, delete, new[ ] , delete[]
其他運算符 ()(函數調用),->(成員通路),,(逗号),[](下标)

不能重載的運算符有:

  成員通路符 .

  成員指針通路運算符 .*

  域運算符 ::

  長度運算符 sizeof 

  條件運算符号 ?:

3. C++運算符重載的形式有哪幾種?

                   1)采用普通函數的重載形式

                   2)采用友元函數的重載形式

                   3)采用成員函數的重載形式

普通函數:

普通函數形式重載運算符,要求待操作的屬性必須是public類型的。

// 普通函數形式 的 運算符重載
#include <iostream>
using namespace std;

class complex		//定義複數類 complex
{
public:
	double real, imag;	//private 成員,分别代表實部和虛部

public:
	complex(double r = 0.0, double i = 0.0)	//構造函數,帶預設參數值
	{
		real = r;
		imag = i;
	}

	void disp()		//成員函數,輸出複數
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};

complex operator+(const complex& obj1, const complex& obj2)		//加+的實作
{
	return complex(obj1.real + obj2.real, obj1.imag + obj2.imag);
}

int main()
{
	complex cx1(1.0, 2.0), cx2(3.0, 4.0), cxRes;

	cxRes = cx1 + cx2;	//相當于cx1.operator+(cx2)
	cxRes.disp();

	return 0;
}
           

友元函數:

用成員函數重載雙目運算符時,左操作數無須用參數輸入,而是通過隐含的this指針傳入,這種做法的效率比較高

此外,操作符還可重載為友元函數形式,這将沒有隐含的參數this指針。對雙目運算符,友元函數有2個參數,對單目運算符,友元函數有一個參數。

p重載為友元函數的運算符重載函數的聲明格式為:

friend 傳回類型operator 運算符 (參數表);

以友元函數形式重寫代碼:

//友員函數形式 的 運算符重載
#include <iostream>
using namespace std;

class complex		//定義複數類complex
{
private:
	double real, imag;	//private成員,分别代表實部和虛部

public:
	complex(double r = 0.0, double i = 0.0)	//構造函數,帶預設參數值
	{
		real = r;
		imag = i;
	}

	friend complex operator + (const complex &, const complex &);	//友元函數形式重載加+
	friend complex operator - (const complex &, const complex &);	//友元函數形式重載減-
	friend complex operator - (const complex &);	//友元函數形式重載一進制-(取反)
	friend complex operator * (const complex &, const complex &);	//友元函數形式重載乘*
	friend complex operator / (const complex &, const complex &);	//友元函數形式重載除*
	friend complex& operator ++(complex &);		//友元函數形式重載前置++
	friend complex operator ++(complex &, int);		//友元函數形式重載後置++

	void disp()														//成員函數,輸出複數
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};

complex operator +(const complex& C1, const complex& C2)		//加+的實作
{
	return complex(C1.real + C2.real, C1.imag + C2.imag);
}

complex operator -(const complex& C1, const complex& C2)		//減-的實作
{
	return complex(C1.real - C2.real, C1.imag - C2.imag);
}

complex operator -(const complex& C1)		//單目-,即取反的實作
{
	return complex(-C1.real, -C1.imag);
}

complex operator *(const complex& C1, const complex& C2)		//乘*的實作
{
	return complex(C1.real * C2.real - C1.imag * C2.imag, C1.real * C2.imag + C1.imag * C2.real);
}

complex operator /(const complex& C1, const complex& C2)		//除*的實作
{
	return complex((C1.real * C2.real + C1.imag + C2.imag) / (C2.real * C2.real + C2.imag * C2.imag),
		(C1.imag * C2.real - C1.real * C2.imag) / (C2.real * C2.real + C2.imag * C2.imag));
}

complex& operator ++(complex& C1)		//前置++的實作
{
	cout << "前置++" << endl;
	C1.real += 1;
	C1.imag += 1;
	return C1;
}

complex operator ++(complex& C1, int)	//後置++的實作,體會和前置++的差別
{
	cout << "後置++" << endl;
	complex ctemp = C1;
	++C1;
	return ctemp;
}

int main()
{
	complex cx1(1.0, 2.0), cx2(3.0, 4.0), cxRes;

	cxRes = cx1 - cx2;	//相當于operator-(cx1, cx2)
	cxRes.disp();

	cxRes = -cx1;		//相當于operator-(cx1)
	cxRes.disp();

	cxRes = cx1 + cx2;	//相當于operator+(cx1, cx2)
	cxRes.disp();

	cxRes = cx1 * cx2;	//相當于operator*(cx1, cx2)
	cxRes.disp();

	cxRes = cx1 / cx2;	//相當于operator/(cx1, cx2)
	cxRes.disp();

	complex cx3(1.0, 1.0), cx4(5.0, 5.0);

	cxRes = ++cx3;		//相當于operator++(cx3)
	cxRes.disp();
	cx3.disp();

	cxRes = cx4++;		//相當于operator++(cx4, 0)
	cxRes.disp();
	cx4.disp();

	//注意下述語句在友元函數形式和成員函數形式的對比。
	cxRes = cx1 + 5;	//相當于operator+(cx1, 5);
	cxRes.disp();

	cxRes = 5 + cx1;	//相當于operator+(5, cx1);
	cxRes.disp();

	return 0;
}
           

成員函數:

成員函數形式的運算符聲明和實作與成員函數類似,首先應當在類定義中聲明該運算符,聲明的具體形式為:

傳回類型  operator 運算符(參數清單);

既可以在類定義的同時定義運算符函數使其成為inline型,也可以在類定義之外定義運算符函數,但要使用作用域限定符“::”,類外定義的基本格式為:

傳回類型  類名::operator 運算符(參數清單)

{

//成員函數形式 的 運算符重載
#include <iostream>
using namespace std;

class complex	//定義複數類 complex
{
private:
	double real, imag;	//private 成員,分别代表實部和虛部

public:
	complex(double r = 0.0, double i = 0.0)	//構造函數,帶預設參數值
	{
		real = r;
		imag = i;
	}

	complex operator+= (const complex &);	//成員函數形式重載加+=

	complex operator+(const complex &);	//成員函數形式重載加+
	complex operator-(const complex &);	//成員函數形式重載減-
	complex operator-();			//成員函數形式重載一進制-(取反)
	complex operator*(const complex &);	//成員函數形式重載乘*
	complex operator/(const complex &);	//成員函數形式重載除*

	complex& operator++();	//成員函數形式重載前置++
	complex operator++(int);	//成員函數形式重載後置++

	void disp()			//成員函數,輸出複數
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};

complex complex::operator+=(const complex& CC)		//加+=的實作
{
	real += CC.real;
	imag += CC.imag;
	return (*this);
}

complex complex::operator+(const complex& CC)		//加+的實作
{
	return complex(real + CC.real, imag + CC.imag);
}

complex complex::operator-(const complex& CC)		//減-的實作
{
	return complex(real - CC.real, imag - CC.imag);
}

complex complex::operator*(const complex& CC)		//乘*的實作
{
	return complex(real * CC.real - imag * CC.imag, real * CC.imag + imag * CC.real);
}

complex complex::operator/(const complex& CC)		//除/的實作
{
	return complex((real * CC.real + imag * CC.imag) / (CC.real * CC.real + CC.imag * CC.imag),
		(imag * CC.real - real * CC.imag) / (CC.real * CC.real + CC.imag * CC.imag));
}

complex complex::operator-()		//單目-,即取反的實作
{
	return complex(-real, -imag);
}

complex& complex::operator++()	//前置++的實作
{
	cout << "前置++" << endl;
	++real;
	++imag;
	return (*this);
}

complex complex::operator++(int)	//後置++的實作,體會和前置++的差別
{
	cout << "後置++" << endl;
	complex cTemp = (*this);	//最終的傳回值的是原來的值,是以需要先儲存原來的值
	++(*this);					//傳回後原來的值需要加1
	return cTemp;
}

int main()
{
	complex cx1(1.0, 2.0), cx2(3.0, 4.0), cxRes;

	cxRes += cx2;		//相當于cxRes.operator+=(cx2)
	cxRes.disp();

	cxRes = cx1 + cx2;	//相當于cx1.operator+(cx2)
	cxRes.disp();

	cxRes = cx1 - cx2;	//相當于cx1.operator-(cx2)
	cxRes.disp();

	cxRes = cx1 * cx2;	//相當于cx1.operator*(cx2)
	cxRes.disp();

	cxRes = cx1 / cx2;	//相當于cx1.operator/(cx2)
	cxRes.disp();

	cxRes = -cx1;		//相當于cx1.operator-()
	cxRes.disp();

	cout << endl;

	complex cx3(1.0, 1.0), cx4(5.0, 5.0);

	cxRes = ++cx3;		//相當于cx3.operator++()
	cxRes.disp();
	cx3.disp();

	cout << endl;

	cxRes = cx4++;		//相當于cx4.operator++(0)
	cxRes.disp();
	cx4.disp();

	cout << endl;

	//注意下述語句在友元函數形式和成員函數形式中的對比。
	cxRes = cx1 + 5;	//相當于cx1.operator+(5) 或 cx1.operator+(complex(5))
	cxRes.disp();

	//	cxRes = 5 + cx1;	//錯誤. 相當于5.operator+(cx1);
	//	cxRes.disp();

	return 0;
}
           

4.C++幾種特殊的運算符重載

(有待補充...)

繼續閱讀