C 中 操作符存在的缺陷

2022-01-12 00:59:58 字數 2339 閱讀 6746

==操作符因為語法簡潔而備受歡迎,但它本身也存在著侷限性,比如繼承或泛型問題。下面讓我們依次來看看吧。

1、==和繼承性問題

關於==運算子在繼承時存在的問題,我們以string型別為例進行說明。

static void main(string args)

執行上面**,依次產生:false、true、true、true。該結果很容易解釋,除了referenceequals方法進行引用比較之外,其他三種比較方法均是值比較。

現在讓我們稍微修改一下上述**,如下所示:

static void main(string args)

再次執行上面**,結果為:false、true、false、true。和上面的結果進行比較,可以發現,只有==操作符的結果發生了改變,這是為什麼呢?

原因就在於==相當於乙個靜態方法,而靜態方法不可能是virtual的,本例中當用==進行比較時,比較的是兩個object型別的變數,儘管我們知道str和str1實際是string型別的,但編譯器並沒有意識到這一點。我們應該牢記的一點就是:對於非虛方法的呼叫而言,具體呼叫哪個實現是在編譯時期就已經做出決定了。具體到我們的例子,就是說,我們宣告了object型別的兩個變數str和str1,那麼編譯器就會生成比較object型別的**。而object類中是沒有==操作符的過載版本實現的,因此,==將進行引用相等性比較,因str和str1是兩個不同的例項物件,故返回false。

由於在面臨繼承時的無能為力,故此是不應選擇==,而應使用equals方法進行判等。接下來看一下equals方法是如何解決這個問題的。

顯然,當使用equals方法進行判等測試時,無論呼叫的是str.equals還是object.equals方法,最終呼叫的都是string型別的override版本實現,故總能計算出我們預期的結果。因此,在存在繼承問題時,應使用equals方法進行判等,而不是==操作符。

最後,從本例中可以看到,當我們將==操作符的運算元強轉到object型別時,它將進行引用相等性測試,總是和referenceequals的結果保持一致,因此,一些開發者就使用這種方式來比較引用相等性,但這樣做的乙個缺點在於:其他的開發者在讀到這樣的**片段時可能產生疑惑。因此在比較引用相等性時最好總是使用referenceequals方法。

2、==和泛型問題

==的另乙個缺陷就是不能和泛型很好地工作在一起。考慮下面的**:

static void equals(t a, t b)

上面**的邏輯很簡單,就是使用==比較兩個t型別的物件。但是編譯上述**將報錯:

之所以報上面的錯誤,是因為t可能代表任意型別,包括基元型別、值型別和引用型別。無法確定傳遞的型別是否實現了==操作符過載。

在c#中,對於泛型型別,我們無法施加這樣的約束,即強制要求傳入的泛型型別t實現==的過載。

現在,我們能夠構建**,僅有的乙個問題就是:equals被限定在僅能接受引用型別,而不能接受值型別。

現在,讓我們還是以之前的字串比較為例,

class program

static void equals(t a, t b) where t : class

}

現在,猜測一下上面**的輸出結果,是true還是false ?如果我們回想起string型別定義了==操作符的過載實現,那麼很可能猜測上面**的結果為true,但實際執行結果卻顯示false,這是為何呢?此時很直觀的猜測就是==操作符計算的是引用判等,而非值判等。下面讓我們看看究竟發生了什麼。

上面的**中,儘管通過where t : class語句限定使得編譯器知道它能對傳入的任何型別應用==操作符進行判等性測試,對應到本例t就是string型別,而且string型別提供了==的過載實現,但編譯器並不曉得泛型型別t是否過載了==操作符,因此,它假定t沒有過載==。編譯器編譯**時假定呼叫的是object基類==操作符,因此,==操作符進行引用判等性測試。

應該始終牢記一點:在對泛型型別t使用==操作符時,編譯器不會使用型別t定義的==運算子過載,相反,它會將t視為object型別,並呼叫object基類的==操作符方法。

接下來讓我們看下equals方法如何解決上面的問題。

static void equals(t a, t b)

可以看出,我們移除了泛型方法的class限定語句,因為能在任何型別上呼叫object.equals方法,之所以使用static限定,是為了避免發出呼叫的例項物件為null,可以看出上面的泛型方法對值型別和引用型別均奏效。

我們再次執行上面的**,結果顯示true。這是因為object.equals方法在執行時將呼叫它的override版本實現,本例中override版實現的定義位於string型別中,該實現進行值判等性測試。

C 中的操作符

c 的精彩世界還離不開其提供的豐富的操作符,按照運算元的個數,c 操作符可分為以下幾類 如果從操作符的作用來看,c 操作符可以分為賦值操作符,算術操作符,關係操作符,邏輯操作符,位操作符和其它操作符。1.賦值操作符 賦值操作符除基本的賦值操作符 之外還包括以下的組合賦值操作符 要注意的是,對於復合的...

C 中的操作符

本想部落格以每週一篇的速度更新,卻未曾料到最近幾周忙到了沒有時間坐下來寫點東西的程度。而這一篇,也因為寫得較為匆忙,望您指出疏漏之處。至於本文參考,可能部分來自於ec中的某個條款,並適當地加以補充。在c 中,為基本型別定義操作符是最常見的任務。例如為乙個自定義型別提供比較操作符,以允許其作為stl容...

c語言操作符 位操作符 移位操作符

1 按位操作符 1.1 按位 與 雙目運算子 僅當兩個運算元都為1時,結果為1,否則為0。參與運算的數以補碼方式出現。例 9 5 1 0000 1001 9的補碼 0000 0101 5的補碼 0000 0001 1的補碼 應用 a 通常將某些位清零或保留某些位。例如 將a的高八位清零,保留低八位,...