c++為了增強**的可讀性引入了運算子過載,對已有的運算子重新進行定義,賦予其另一種功能,運算子過載是具有特殊函式名的函式,也具有其返回值型別,函式名字以及引數列表,其返回值型別與引數列表與普通的函式類似。函式名字:operator後面接需要過載的運算子符號。
函式原型:type operator操作符 (引數列表)。
■1、不能通過連線其他符號來建立新的操作符:比如operator@。
■2、過載操作符必須有乙個類型別,沒有型別那麼根本沒有意義。
■3、用於內建型別的操作符,其含義不能改變,例如:內建的整數+,不能改變其含義。
■4、作為類成員的運算子過載函式時,其形參看起來比運算元數目少1個,其中成員函式的操作符有乙個預設的形參this,限定為第乙個形參。對於全域性的運算子過載函式的引數和運算元目的個數相等。
■5、.*、::、sizeof、?:、. 這5種運算子不能過載。
class
date
private
:int _year;
int _month;
int _day;};
//返回引用可以實現鏈式程式設計,ostream和istream用非常量,在輸入或輸出時要改變狀態,用引用是因為我們無法直接複製乙個ostream和istream物件。
ostream&
operator
<<
(ostream& _cout,
const date& d)
返回引用可以實現鏈式程式設計,date宣告為非常量因為我們本來的目的就是將資料讀入到這個物件當中。
istream&
operator
>>
(istream& _cin, date& d)
//輸入運算子必須處理輸入可能失敗的情況,如果輸入失敗應該將引數恢復成原始的狀態。
intmain()
與iostream 標準庫相容的輸入輸出運算子必須是普通的非成員函式,而不是類的成員函式。否則,它們的左側運算物件將是我們的類的乙個物件:
date date;
date/如果operator《是date的成員
我們無法給標準庫中的類新增任何成員。io運算子通常需要讀寫類的非共有資料成員,所以io運算子一般被宣告為友元。
賦值符常常初學者的混淆。這是毫無疑問的,因為』=』在程式設計中是最基本的運算子,可以進行賦值操作,也能引起拷貝建構函式的呼叫。當物件沒有初始化而賦值時會引起拷貝建構函式的呼叫,當已經初始化了而賦值時會呼叫賦值運算過載函式的呼叫。■
1、返回值(返回*this)。
■2、檢測是否自己給自己賦值。
■3、乙個類如果沒有顯式定義賦值運算子過載,編譯器也會生成乙個,完成物件按位元組序的值拷貝(淺拷貝)。當有指標時,呼叫析構函式會引發記憶體問題。
**例項1:
class
person
//當準備給兩個相同物件賦值時,檢查是否自己給自己賦值
person&
operator=(
const person& person)
return
*this;}
private
: string _name;
int _age;};
void
test()
**例項2:
//乙個類預設建立 預設構造、析構、拷貝構造 operator=賦值運算子 進行簡單的值傳遞(淺拷貝)
class
person
//過載賦值運算子
person&
operator=(
const person& person)
//重新申請空間,進行深拷貝
this
->_name =
newchar
[strlen
(person._name)+1
];strcpy
(this
->_name,person._name)
;this
->_age = person._age;
return
*this;}
//呼叫析構函式
~person()
}private
:char
* _name;
int _age;
};
有關深淺拷貝問題參考我的另一篇部落格:c++入門–建構函式、拷貝建構函式、析構函式
普通的過載形式無法同時定義前置和後置運算子。前置和後置版本使用的是同乙個符號,意味著其過載版本所用的名字將是相同的,並且運算物件的數量和型別也相同。後置版本接受乙個額外的int型別的形參(operator++(int))。當我們使用後置運算子時,編譯器為這個形式提供乙個值為0的引數。為了和內建版本保持一致,前置運算子應該返回遞增或遞減後物件的引用。而後置運算子應該返回物件的原值(遞增或遞減之前的值),返回的形式是乙個臨時值而非引用。
例項**:
class
integer
//前置++
integer&
operator++(
)//後置++
integer operator++(
int)
//前置--
integer&
operator--(
)//後置--
integer&
operator--(
int)
private
:int num;};
ostream&
operator
<<
(ostream& cout,integer &it)
結論:呼叫**時候,要優先選擇字首形式,除非確實需要字尾形式返回的原值,字首和字尾形式語義上是等價的,字首形式少建立了乙個臨時物件,所以效率經常會略高一些。
表示容器的類通常可以通過元素的容器中的位置訪問元素,這些類一般會定義下標運算子 operator [ ] 。下標運算子必須是成員函式,並且下標運算子返回所訪問元素的引用,這樣做為了能夠作為左值修改元素的值。例項**:
class
strvec
const std::string&
operator
(std::size_t n)
const
//當定義常量物件時,只能呼叫這個函式
private
: std::string *elements;
};
如果乙個類包含下標運算子,則它通常會定義兩個版本,乙個返回普通引用,另乙個是類的常量成員並且返回常量引用。當我們對常量物件取下標時,不能為其賦值。
如果new出來的物件,就要讓程式設計師自己去釋放,但是實際開發中常常會忘記釋放物件引起記憶體洩漏。因此我們可以用智慧型指標來託管這個物件,所以物件的釋放就不用程式設計師操心了,但是有了智慧型指標想要和指標一樣就要過載-> 和 * 運算子。**例項:
class
person
void
showage()
~person()
private
:int m_age;};
//智慧型指標
//用來託管自定義型別的物件,讓物件進行自動釋放
class
smartpointer
//過載->讓智慧型指標物件person* p 一樣去使用
person*
operator
->()
person&
operator*(
)~smartpointer()
}private
: person* person;};
void
test01()
■1、=、、()和 -> 操作符只能通過成員函式進行過載。
■2、《和》只能通過全域性函式配合友元函式進行過載。
■3、不要過載||和&&因為無法實現短路規則。
運算子建議使用
所有的一元運算子
成員=、、()、->、*
必須是成員
+=、-=、/=、*=、^=、&=、!=、%=
成員其他二元運算子
非成員
C 運算子過載 過載特殊運算子
賦值運算子用於同類物件間的相互賦值。賦值運算子只能被過載為類的非靜態成員函式,不能過載為友元函式和普通函式。對於使用者自定義的類而言,如果沒有過載賦值運算子,那麼c 編譯器會為該類提供乙個預設的過載賦值運算子成員函式。預設賦值運算子的工作方式是按位對拷,將等到右邊物件的非靜態成員拷貝給等號左邊的物件...
C 運算子過載賦值運算子
自定義類的賦值運算子過載函式的作用與內建賦值運算子的作用類似,但是要要注意的是,它與拷貝建構函式與析構函式一樣,要注意深拷貝淺拷貝的問題,在沒有深拷貝淺拷貝的情況下,如果沒有指定預設的賦值運算子過載函式,那麼系統將會自動提供乙個賦值運算子過載函式。賦值運算子過載函式的定義與其它運算子過載函式的定義是...
C 運算子過載轉換運算子
為什麼需要轉換運算子?大家知道對於內建型別的資料我們可以通過強制轉換符的使用來轉換資料,例如 int 2.1f 自定義類也是型別,那麼自定義類的物件在很多情況下也需要支援此操作,c 提供了轉換運算子過載函式 它使得自定義類物件的強轉換成為可能。轉換運算子的生命方式比較特別,方法如下 operator...