C Prime14章學習筆記

2021-10-03 16:09:40 字數 4325 閱讀 5523

過載的運算子是具有特殊名字的函式,它由關鍵字 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 圖省事...