C++主要操作符重載的定義和總結

C++中預定義的運算符的操作對象只能是基本數據類型,實際上,對于很多用戶自定義類型,也需要有類似的運算操作。例如:?
class?complex?
{?
?public:?
??complex(double?r=0.0,double?I=0.0){real=r;imag=I;}?
??void?display();?
?private:?
??double?real;?
??double?imag;?
};?
complex?a(10,20),b(5,8);?
“a+b”運算如何實現?這時候我們需要自己編寫程序來說明“+”在作用于complex類對象時,該實現什么樣的功能,這就是運算符重載。運算符重載是對已有的運算符賦予多重含義,使同一個運算符作用于不同類型的數據導致不同類型的行為。?
運算符重載的實質是函數重載。在實現過程中,首先把指定的運算表達式轉化為對運算符函數的調用,運算對象轉化為運算符函數的實參,然后根據實參的類型來確定需要調用達標函數,這個過程愛編譯過程中完成。?

一、?運算符重載的規則?
運算符重載規則如下:?
①、?C++中的運算符除了少數幾個之外,全部可以重載,而且只能重載C++中已有的運算符。?
②、?重載之后運算符的優先級和結合性都不會改變。?
③、?運算符重載是針對新類型數據的實際需要,對原有運算符進行適當的改造。一般來說,重載的功能應當與原有功能相類似,不能改變原運算符的操作對象個數,同時至少要有一個操作對象是自定義類型。?
不能重載的運算符只有五個,它們是:成員運算符“.”、指針運算符“*”、作用域運算符“::”、“sizeof”、條件運算符“?:”。?
運算符重載形式有兩種,重載為類的成員函數和重載為類的友元函數。?
運算符重載為類的成員函數的一般語法形式為:?
函數類型?operator?運算符(形參表)?
{?
??函數體;?
}?
運算符重載為類的友元函數的一般語法形式為:?
friend?函數類型?operator?運算符(形參表)?
{?
??函數體;?
}?
其中,函數類型就是運算結果類型;operator是定義運算符重載函數的關鍵字;運算符是重載的運算符名稱。?
當運算符重載為類的成員函數時,函數的參數個數比原來的操作個數要少一個;當重載為類的友元函數時,參數個數與原操作數個數相同。原因是重載為類的成員函數時,如果某個對象使用重載了的成員函數,自身的數據可以直接訪問,就不需要再放在參數表中進行傳遞,少了的操作數就是該對象本身。而重載為友元函數時,友元函數對某個對象的數據進行操作,就必須通過該對象的名稱來進行,因此使用到的參數都要進行傳遞,操作數的個數就不會有變化。?
運算符重載的主要優點就是允許改變使用于系統內部的運算符的操作方式,以適應用戶自定義類型的類似運算。?

二、?運算符重載為成員函數?
對于雙目運算符B,如果要重載B為類的成員函數,使之能夠實現表達式oprd1?B?oprd2,其中oprd1為類A的對象,則應當把B重載為A類的成員函數,該函數只有一個形參,形參的類型是oprd2所屬的類型。經過重載后,表達式oprd1?B?oprd2?就相當于函數調用oprd1.operator?B(oprd2).?
對于前置單目運算符U,如“-”(負號)等,如果要重載U為類的成員函數,用來實現表達式U?oprd,其中oprd為A類的對象,則U應當重載為A類的成員函數,函數沒有形參。經過重載之后,表達式U?oprd相當于函數調用oprd.operator?U().?
對于后置運算符“++”和“-?-”,如果要將它們重載為類的成員函數,用來實現表達式oprd++或oprd--,其中oprd為A類的對象,那么運算符就應當重載為A類的成員函數,這時函數要帶有一個整型形參。重載之后,表達式oprd++和oprd—就想當于函數調用oprd.operator++(0)和oprd.operator—(0);?
運算符重載就是賦予已有的運算符多重含義。通過重新定義運算符,使它能夠用于特定類的對象執行特定的功能,這便增強了C++語言的擴充能力。

?

1.?運算符重載的作用:

運算符重載允許C/C++的運算符在用戶定義類型(類)上擁有一個用戶定義的意義。重載的運算符是函數調用的語法修飾:

class Fred

{

public:

// ...

};

?

#if 0

//?沒有算符重載:

Fred add(Fred, Fred);

Fred mul(Fred, Fred);

?

Fred f(Fred a, Fred b, Fred c)

{

return add(add(mul(a,b), mul(b,c)), mul(c,a)); //?哈哈,多可笑...

}

#else

//?有算符重載:

Fred operator+ (Fred, Fred);

Fred operator* (Fred, Fred);

?

Fred f(Fred a, Fred b, Fred c)

{

return a*b + b*c + c*a;

}

#endif

?

2.?可以用作重載的運算符:

算術運算符:+,-,*,/,%,++,--;

位操作運算符:&,|,~,^,<<,>>

邏輯運算符:!,&&,||;

比較運算符:<,>,>=,<=,==,!=;

賦值運算符:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=;

其他運算符:[],(),->,,(逗號運算符),new,delete,new[],delete[],->*。

下列運算符不允許重載:

.,.*,::,?:

?

3.?運算符重載后,優先級和結合性:

用戶重載新定義運算符,不改變原運算符的優先級和結合性。這就是說,對運算符重載不改變運算符的優先級和結合性,并且運算符重載后,也不改變運算符的語法結構,即單目運算符只能重載為單目運算符,雙目運算符只能重載雙目運算符。

?

4.?編譯程序如何選用哪一個運算符函數:

運算符重載實際是一個函數,所以運算符的重載實際上是函數的重載。編譯程序對運算符重載的選擇,遵循著函數重載的選擇原則。當遇到不很明顯的運算時,編譯程序將去尋找參數相匹配的運算符函數。

?

5.?重載運算符有哪些限制:

(1)?不可臆造新的運算符。必須把重載運算符限制在C++語言中已有的運算符范圍內的允許重載的運算符之中。

(2)?重載運算符堅持4個“不能改變”。

·不能改變運算符操作數的個數;

·不能改變運算符原有的優先級;

·不能改變運算符原有的結合性;

·不能改變運算符原有的語法結構。

?

6.?運算符重載時必須遵循哪些原則:

運算符重載可以使程序更加簡潔,使表達式更加直觀,增加可讀性。但是,運算符重載使用不宜過多,否則會帶來一定的麻煩。

(1)?重載運算符含義必須清楚。

(2)?重載運算符不能有二義性。

運算符重載函數的兩種形式

運算符重載的函數一般地采用如下兩種形式:成員函數形式和友元函數形式。這兩種形式都可訪問類中的私有成員。

?

1.?重載為類的成員函數

這里先舉一個關于給復數運算重載復數的四則運算符的例子。復數由實部和虛部構造,可以定義一個復數類,然后再在類中重載復數四則運算的運算符。先看以下源代碼:

#include?<iostream.h>

?

class complex

{

public:

complex() { real=imag=0; }

complex(double r, double i)

{

real = r, imag = i;

}

complex operator +(const complex &c);

complex operator -(const complex &c);

complex operator *(const complex &c);

complex operator /(const complex &c);

friend void print(const complex &c);

private:

double real, imag;

};

?

inline complex complex::operator +(const complex &c)

{

return complex(real + c.real, imag + c.imag);

}

?

inline complex complex::operator -(const complex &c)

{

return complex(real - c.real, imag - c.imag);

}

?

inline complex complex::operator *(const complex &c)

{

return complex(real * c.real - imag * c.imag, real * c.imag + imag * c.real);

}

?

inline complex complex::operator /(const complex &c)

{

return complex((real * c.real + imag + c.imag) / (c.real * c.real + c.imag * c.imag),

(imag * c.real - real * c.imag) / (c.real * c.real + c.imag * c.imag));

}

?

void print(const complex &c)

{

if(c.imag<0)

cout<<c.real<<c.imag<<'i';

else

cout<<c.real<<'+'<<c.imag<<'i';

}

?

void main()

{

complex c1(2.0, 3.0), c2(4.0, -2.0), c3;

c3 = c1 + c2;

cout<<"/nc1+c2=";

print(c3);

c3 = c1 - c2;

cout<<"/nc1-c2=";

print(c3);

c3 = c1 * c2;

cout<<"/nc1*c2=";

print(c3);

c3 = c1 / c2;

cout<<"/nc1/c2=";

print(c3);

c3 = (c1+c2) * (c1-c2) * c2/c1;

cout<<"/n(c1+c2)*(c1-c2)*c2/c1=";

print(c3);

cout<<endl;

}

?

該程序的運行結果為:

c1+c2=6+1i

c1-c2=-2+5i

c1*c2=14+8i

c1/c2=0.45+0.8i

(c1+c2)*(c1-c2)*c2/c1=9.61538+25.2308i

?

在程序中,類complex定義了4個成員函數作為運算符重載函數。將運算符重載函數說明為類的成員函數格式如下:

<類名>?operator?<運算符>(<參數表>)

其中,operator是定義運算符重載函數的關鍵字。

程序中出現的表達式:

????c1+c2

?

編譯程序將給解釋為:

?

??c1.operator+(c2)

?

其中,c1和c2是complex類的對象。operator+()是運算+的重載函數。

該運算符重載函數僅有一個參數c2。可見,當重載為成員函數時,雙目運算符僅有一個參數。對單目運算符,重載為成員函數時,不能再顯式說明參數。重載為成員函數時,總時隱含了一個參數,該參數是this指針。this指針是指向調用該成員函數對象的指針。

?

2.?重載為友元函數:

運算符重載函數還可以為友元函數。當重載友元函數時,將沒有隱含的參數this指針。這樣,對雙目運算符,友元函數有2個參數,對單目運算符,友元函數有一個參數。但是,有些運行符不能重載為友元函數,它們是:=,(),[]和->。

重載為友元函數的運算符重載函數的定義格式如下:

?

??friend?<類型說明符>?operator?<運算符>(<參數表>)

??{……}

?

下面用友元函數代碼成員函數,重載編寫上述的例子,程序如下:

?

#include?<iostream.h>

?

class complex

{

public:

complex() { real=imag=0; }

complex(double r, double i)

{

real = r, imag = i;

}

friend complex operator +(const complex &c1, const complex &c2);

friend complex operator -(const complex &c1, const complex &c2);

friend complex operator *(const complex &c1, const complex &c2);

friend complex operator /(const complex &c1, const complex &c2);

friend

void print(const complex &c);

private:

double real, imag;

};

?

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, 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));

}

?

void print(const complex &c)

{

if(c.imag<0)

cout<<c.real<<c.imag<<'i';

else

cout<<c.real<<'+'<<c.imag<<'i';

}

?

void main()

{

complex c1(2.0, 3.0), c2(4.0, -2.0), c3;

c3 = c1 + c2;

cout<<"/nc1+c2=";

print(c3);

c3 = c1 - c2;

cout<<"/nc1-c2=";

print(c3);

c3 = c1 * c2;

cout<<"/nc1*c2=";

print(c3);

c3 = c1 / c2;

cout<<"/nc1/c2=";

print(c3);

c3 = (c1+c2) * (c1-c2) * c2/c1;

cout<<"/n(c1+c2)*(c1-c2)*c2/c1=";

print(c3);

cout<<endl;

}

該程序的運行結果與上例相同。前面已講過,對又目運算符,重載為成員函數時,僅一個參數,另一個被隱含;重載為友元函數時,有兩個參數,沒有隱含參數。因此,程序中出現的?c1+c2

編譯程序解釋為:

?

??operator+(c1, c2)

?

調用如下函數,進行求值,

?

??complex operator +(const coplex &c1, const complex &c2)

?

3.?兩種重載形式的比較

一般說來,單目運算符最好被重載為成員;對雙目運算符最好被重載為友元函數,雙目運算符重載為友元函數比重載為成員函數更方便此,但是,有的雙目運算符還是重載為成員函數為好,例如,賦值運算符。因為,它如果被重載為友元函數,將會出現與賦值語義不一致的地方。?其他運算符的重載舉例

1).下標運算符重載

由于C語言的數組中并沒有保存其大小,因此,不能對數組元素進行存取范圍的檢查,無法保證給數組動態賦值不會越界。利用C++的類可以定義一種更安全、功能強的數組類型。為此,為該類定義重載運算符[]。

下面一個例子:

?

#include?<iostream.h>

?

class CharArray

{

public:

CharArray(int l)

{

Length = l;

Buff = new char[Length];

}

~CharArray() { delete Buff; }

int GetLength() { return Length; }

char & operator [](int i);

private:

int Length;

char * Buff;

};

?

char & CharArray::operator [](int i)

{

static char ch = 0;

if(i<Length&&i>=0)

return Buff[i];

else

{

cout<<"/nIndex out of range.";

return ch;

}

}

?

void main()

{

int cnt;

CharArray string1(6);

char * string2 = "string";

for(cnt=0; cnt<8; cnt++)

string1[cnt] = string2[cnt];

cout<<"/n";

for(cnt=0; cnt<8; cnt++)

cout<<string1[cnt];

cout<<"/n";

cout<<string1.GetLength()<<endl;

}

該數組類的優點如下:

(1)?其大小不一定是一個常量。

(2)?運行時動態指定大小可以不用運算符new和delete。

(3)?當使用該類數組作函數參數時,不心分別傳遞數組變量本身及其大小,因為該對象中已經保存大小。

在重載下標運算符函數時應該注意:

(1)?該函數只能帶一個參數,不可帶多個參數。

(2)?不得重載為友元函數,必須是非static類的成員函數。?2).?重載增1減1運算符.

增1減1運算符是單目運算符。它們又有前綴和后綴運算兩種。為了區分這兩種運算,將后綴運算視為又目運算符。表達式

????obj++或obj--

被看作為:

????obj++0或obj--0

下面舉一例子說明重載增1減1運算符的應用。

?

#include?<iostream.h>

?

class counter

{

public:

counter() { v=0; }

counter operator ++();

counter operator ++(int );

void print() { cout<<v<<endl; }

private:

unsigned v;

};

?

counter counter::operator ++()

{

v++;

return *this;

}

?

counter counter::operator ++(int)

{

counter t;

t.v = v++;

return t;

}

?

void main()

{

counter c;

for(int i=0; i<8; i++)

c++;

c.print();

for(i=0; i<8; i++)

++c;

c.print();

}

?

3).?重載函數調用運算符

可以將函數調用運算符()看成是下標運算[]的擴展。函數調用運算符可以帶0個至多個參數。下面通過一個實例來熟悉函數調用運算符的重載。

?

#include?<iostream.h>

?

class F

{

public:

double operator ()(double x, double y) const;

};

?

double F::operator ()(double x, double y) const

{

return (x+5)*y;

}

?

void main()

{

F f;

cout<<f(1.5, 2.2)<<endl;

}

轉載于:https://www.cnblogs.com/D-DZDD/p/7210567.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/455118.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/455118.shtml
英文地址,請注明出處:http://en.pswp.cn/news/455118.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

原生JS數組去重的幾種方法

有時候我們做項目的時候往往會需要把數組里面一些重復的項去掉,但是原生JS有排序,有篩選等等,但是就是沒有數組去重怎么辦呢?這能怎么辦,自己手動實現嘛。(以下代碼直接在原型上添加的的方法,為…

單例設計模式-枚舉

枚舉 枚舉應用實例 代碼演示 package com.atguigu.principle.singleton.type08;/** */ public class SingletonTest08 {public static void main(String[] args) {Singleton instance Singleton.INSTANCE;Singleton instance2 Singleton.INSTANCE;System.out.println(inst…

拋物線交點式公式_拋物線交點式

以下是范文網www zhuodaoren com 分享的6 已知拋物線與軸兩交點在軸同側,它們的距離的平方等于,則的值為( ),希望能幫助到大家!(一)6 已知拋物線與軸兩交點在軸同側,它們的距離的平方等于,則的值為( )函數與一元二次方…

學習的動力

要有自學的意識,這是一個知識不斷更新、不斷涌現的時代,大學里的很多知識是過時的,就算入校時是熱門行業的但很可能四年后畢業找工作時已經變成了夕陽產業,學習是一種能力,但首先是一種態度,一個人想在快速…

java面向對象之父類的引用指向子類的對象

1 package Text; 2 3 public class Job { 4 public void dowork(){ 5 6 } 7 } 1 package Text; 2 3 public class Luosidao extends Job{ 4 public void dowork(){ 5 System.out.println("螺絲刀擰螺絲。。。"); 6 } 7 } 1 packa…

單例模式在JDK應用的源碼分析

單例模式在JDK應用的源碼分析 單例模式在jdk中的源碼分析 在我們JDK中,java.lang.Runtime就是經典的單例模式(惡漢式) 代碼分析Debug源碼代碼說明 public class Runtime {private static Runtime currentRuntime new Runtime();/*** Returns the runtime object associate…

lisp語言cond和if套用_LISP - 決策

決策結構需要程序員指定一個或多個條件由程序進行評估或測試,以及要執行的語句或語句如果條件被確定為true,如果條件被確定為false那么選擇要執行其他語句。下面是在大多數編程語言中一個典型的決策結構的一般形式為:LISP提供了以下類型的決策…

H264基本概念之 宏塊、片和片組

這幾個概念對比音頻信號處理可是全新的,下面簡要介紹一下定義和作用: 1、宏塊(Macro Block):一個編碼圖像首先要劃分成多個塊(4x4 像素)才能進行處理,顯然宏塊應該是整數個塊組成&…

CodeVS 1044 攔截導彈(DP)

題目大意&#xff1a; http://codevs.cn/problem/1044/ 第一問題就是求序列的最長遞減數列的長度&#xff0c;第二問就是求數列的最長遞增序列的長度。 代碼&#xff1a; #include <iostream>using namespace std;int arr[30] {0}; int dp[30] {0}; int mp[30] {0};in…

鏈表(Linked List)之單鏈表

原文地址:傳送門 鏈表(Linked List)介紹 鏈表是有序的列表&#xff0c;但是它在內存中是存儲如下 小結: 鏈表是以節點的方式來存儲,是鏈式存儲 每個節點包含 data 域&#xff0c; next 域&#xff1a;指向下一個節點. 如圖&#xff1a;發現鏈表的各個節點不一定是連續存儲…

有字符csv文件導入matlab_Matlab:如何讀取CSV文件以及如何讀取帶有字符串數據項的CSV文件...

CSV&#xff0c;逗號分開的文件&#xff0c;如果能快速的讀取這些文件中的數據&#xff0c;無疑會幫助我們解決很多問題。1、 只有數據的CSV文件&#xff0c;CSV file that includes only numbers.As an example, create a text file, named as data.csv if you prefer, which …

xchg_mb_border()

顧名思義&#xff0c; xchg_mb_border() 交換 MB 邊界的像素。閱讀代碼可知&#xff0c;交換雙方為邊界緩存 (left_border,top_borders) 與重建圖象中的相應數據。其中 xchg 參數是否為 1 決定&#xff0c;在從邊界緩存賦值到重建圖象的同時&#xff0c;是否保存重建圖象的數據…

Introduction to the Optimizer --cbo

http://docs.oracle.com/cd/B10500_01/server.920/a96533/optimops.htm

統計字符串中某個字出現的次數

package ch11;import java.util.Scanner;/** * Created by liwenj on 2017/7/21. */public class T6 { public static void main(String[] args) { String w "我愛你中國&#xff0c;我愛你故鄉"; String a "愛"; int k0; …

jedispool redis哨兵_通過java哨兵JedisSentinelPool代碼示例連接對配置的redis哨兵主從模式進行測試驗證...

一、前言本文章通過關于java的jedis(2.6.0)的redis客戶端連接驅動包&#xff0c;對配置的redis哨兵主從讀寫模式配置進行示例代碼驗證&#xff0c;詳細參見具體配置步驟&示例代碼說明部分。二、配置步驟1. 安裝redis(參考其他文章教程),并配置主從模式(參考其他相關文章&am…

鏈表(Linked List)之雙向鏈表

雙向鏈表應用實例 使用帶head頭的雙向鏈表實現 –水滸英雄排行榜 管理單向鏈表的缺點分析: 單向鏈表&#xff0c;查找的方向只能是一個方向&#xff0c;而雙向鏈表可以向前或者向后查找。 單向鏈表不能自我刪除&#xff0c;需要靠輔助節點 &#xff0c;而雙向鏈表&#xff…

H264 解碼耗時分析

在數字基帶處理器上代碼的最佳放置 美國模擬器件公司 Jose Fridman   在手機等嵌入式系統中&#xff0c;除了處理器執行時間外&#xff0c;最重要的資源就是設備總線和存儲器接口。本文將介紹一種在使用指令高速緩存時其帶寬消耗的基礎上&#xff0c;統計分析高速緩存所采用…

CentOS 7 使用iptables防火墻

# 停止firewalld服務 systemctl stop firewalld systemctl mask firewalld # 安裝iptables-services yum install iptables-services Enable the service at boot-time: # 啟動iptables服務 systemctl enable iptables # 管理iptables systemctl [stop|start|restart] ip…

Linux命令之useradd和userdel(添加、刪除用戶)

一、【useradd】&#xff1a;添加用戶命令 1.作用useradd或adduser命令用來建立用戶帳號和創建用戶的起始目錄&#xff0c;使用權限是超級用戶。 2.格式 useradd [-d home] [-s shell] [-c comment] [-m [-k template]] [-f inactive] [-e expire ] [-p passwd] [-r] name 3.主…

鏈表(Linked List)之環形鏈表

原文地址:傳送門 單向環形鏈表應用場景 Josephu(約瑟夫、約瑟夫環) 問題 Josephu 問題為&#xff1a;設編號為1&#xff0c;2&#xff0c;… n的n個人圍坐一圈&#xff0c;約定編號為k&#xff08;1<k<n&#xff09;的人從1開始報數&#xff0c;數到m 的那個人出列&…