過載的運算子是具有特殊名字的函式,它由關鍵字 operator與後面定義的符號組成,過載函式包含返回型別,引數列表以及函式體。過載運算子的引數數量與該運算子的作用的運算物件數量一樣多。
如果乙個運算子函式是成員函式,則其第乙個運算物件繫結到this指標上。
注意:對於乙個運算子函式來說,它或者是類的成員或者至少含有乙個類型別的引數。
同時只能過載已有的運算子,而不能發明新的符號。
對於乙個過載的運算子來說,其優先順序與結合律與對應的內建運算子保持一致
直接呼叫乙個過載運算子
通常情況下,我們將運算子作用於型別正確的實參,從而以這種間接方式呼叫過載的運算子函式。然而,我們也能像普通函式一樣呼叫運算子函式,然後傳入數量正確型別恰當的實參
data1+data2;
//普通的表示式
operator
+(data1,data2)
;
這兩次呼叫是等價的,他們都呼叫了非成員函式operator+,傳入data1為第乙個實參,傳入 data2為第二個實參。
接下來像呼叫其他成員一樣顯示的呼叫成員運算子,具體做法是,首先制定執行函式物件和指標的名字,然後使用運算子訪問希望呼叫的函式。
data1 +
= data2;
//基於呼叫的表示式
data1.operator+
=(data2)
;//對成員運算子函式的等價呼叫
某些運算子不應該被過載
通常情況下不應該過載逗號,取位址,邏輯與和邏輯或運算子。
賦值和復合運算子
賦值運算子的行為與復合版本的類似:賦值之後,左側運算物件和右側運算物件的值相等,並且運算子應返回左側物件的乙個引用。過載的賦值應該繼承非違背其內建版本的含義。
選擇作為成員還是非成員
準則:賦值(=),下標([ ]),呼叫(())和成員訪問箭頭(->)運算子必須是成員。
復合賦值運算子一般來說是成員,但並非必須。
改變運算狀態的運算子或者給定型別密切相關的運算子,如遞增,遞減和解引用運算子,通常應該是成員、
具有對稱性的運算子可以轉換為任意運算物件,如算術,相等性,關係,位運算子等,因此它應該包含普通的非成員函式
14.2.1過載輸出運算子<<
tips:通常輸出運算子應該主要負責列印物件的內容而非控制格式,輸出運算子不應當列印換行運算子。
輸入輸出運算子必須是非成員函式。
14.2.2過載輸入運算子
輸入時執行錯誤,和標識錯誤
標識錯誤:輸入運算子可能檢測bookno是否符合格式,
14.3.1相等運算子
注意事項:相等運算子和不等運算子應該同時定義。
乙個賦值運算子的例子
strvec &strvec::oprerator=
(initializer_list il)
const string&
operator
(size_t n)
const
private
: string *elements;
區分前置和後置運算子,後置版本接受乙個額外的(int)形參
對於後置版本來說,在遞增物件之前需要記錄物件的狀態。
如果過載了函式呼叫運算子,也可以像使用函式一樣使用該類的物件。因為這樣的類同時也能儲存狀態。
struct absint
;
這個類只定義了一種操作,函式呼叫運算子,它接受乙個int型別的實參,然後返回實參的絕對值。
令乙個absint物件作用於乙個實參列表
int i =-42
;absint absobj;
int ui =
absobj
(i);
如果定義了呼叫運算子,則該類的物件稱為函式物件。
14.8.1 lamba為函式物件
14.8.2 標準庫定義的函式物件
14.8.3可呼叫物件與function
由於存在幾個呼叫物件共享同一種呼叫形式的現象。因此,需要定義乙個函式表用於儲存這些可呼叫物件的指標。這時候需要呼叫function的標準庫來解決問題。
function是乙個模板,在建立具體型別時必須提供額外的資訊
function<
int(
int,
int)
>
對於不同型別有
function<
int(
int,
int)
>f1 = add //函式指標
function<
int(
int,
int)
>f2 = divide //函式物件類的物件
function<
int(
int,
int)
>f3 =
(int i,
int j)
;//lambda
14.9.1類型別轉換
型別轉換運算子是類的一種特殊成員函式,它負責將乙個型別的值轉換為其他型別,一般如下
operator
type()
const
其中type表示某種型別。型別運算子可以面向任意型別進行定義。(除了void)因此,不允許轉換為陣列或函式型別。但允許轉換為指標型別或引用型別。
定義含有型別轉換的運算子
class
smallint
operator
int(
)const
private
: std::size_t val;
};
small int 定義了向類型別的轉換和從類型別像其它型別的轉換。其中,建構函式將算術運算子的值轉換為smallint物件。
smallint si;
si =4;
//首先將4隱式的轉換為smallint,然後呼叫operator=函式
si +3;
//將si轉換為隱式的int再呼叫加法。
由於型別轉換運算子是隱式執行的。因此無法傳遞實參,也不能使用任何形參。同時,每個型別轉換函式返回乙個對應型別的值。
class
smallint
;operator
int(smallint&
)//錯誤:不是成員函式
class
smallint
由於型別轉換運算子可能產生意外,為了防止這種意外發生,往往採用顯示運算子。
class
smallint
};
此時只能顯示的進行型別轉換
static_cast
<
int>si +
3;
當然,這些規定存在著乙個例外。當表示式出現在下列位置時轉換將隱式的執行。
if,while與do語序的條件部分
for語句的條件表示式
邏輯非,與,或運算子的運算物件
條件運算子的條件表示式
轉換為bool
無論在什麼時候在條件中使用流物件,都會使用i/o型別的operator bool
while
(cin>>value)
;
while語句輸入條件執行運算子,它負責將輸入讀到value並返回cin,為條件求值,cin被istream operator bool進行了隱式轉換,真返回true;
14.9.2 避免二義性型別轉換
如果乙個類中包含乙個或多個型別轉換。則必須保證類型別和目標型別之間只有一種轉換方式。
在兩種情況下會產生二義性。第一種情況是兩個類提供相同的型別轉換。第二種情況是定義了多個轉換規則,而這些規則可以通過其他規則聯絡在一起。
要正確的設計類的過載運算子,轉換建構函式及型別轉換函式。
(1)不要令兩個類執行相同的型別轉換,如果foo類有乙個接受bar類物件的建構函式,則不要在bar類中定義foo的轉換構造符。
(2)避免轉換的目標是內建算術型別的型別轉換,特別是定義了乙個轉換成算術型別的型別轉換時。不要再定義接受算術型別的過載運算子。如果使用者需要使用這樣的運算子,則型別轉換操作將轉換你型別的物件,然後使用內建的運算子。不要定義轉換到多種型別的算術轉換。
過載函式與使用者定義的型別轉換。
C Prime13章學習筆記
13.1.1 拷貝建構函式 當乙個建構函式的第乙個引數是自身型別的引用,且任何額外引數都有預設值,則此建構函式為拷貝建構函式 class foo hashptr 在進行拷貝的過程中,有可能指標指向同一記憶體,在呼叫構析函式時,會發現函式已經釋放。13.1.5 使用 default 我們可以通過將拷貝...
C Prime 第14章 前30題
過載運算子與內建運算子 區別 1 某些運算物件的求值規則無法在過載運算子中儲存下來.比如 和 的短路求值特性被捨棄.2 過載運算子必須要求至少有乙個成員是class型別 相同 1 一般來說,優先順序,結合律和運算元的數目是一致的.2 一般來說,表達的邏輯是相同的.friend std istream...
C Prime 第14章後23題
智慧型指標或內建型別,可以自己管理自己擁有的資源,於是使用編譯器合成的拷貝控制函式就滿足要求了.classx private strblobptr ptr 過載的函式呼叫運算子最少接受0個物件,最多接受無限個物件.pragma once include using namespace std 圖省事...