日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ 运算符重载(二) | 类型转换运算符,二义性问题

發(fā)布時間:2023/12/13 c/c++ 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ 运算符重载(二) | 类型转换运算符,二义性问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 類型轉(zhuǎn)換運算符
    • 概念
    • 避免過度使用類型轉(zhuǎn)換函數(shù)
    • 解決上述問題的方法
      • 轉(zhuǎn)換為 bool
      • 顯式的類型轉(zhuǎn)換運算符
    • 類型轉(zhuǎn)換二義性
    • 重載函數(shù)與類型轉(zhuǎn)換結合導致的二義性
    • 重載運算符與類型轉(zhuǎn)換結合導致的二義性


類型轉(zhuǎn)換運算符

概念

類型轉(zhuǎn)換運算符(conversion operator)是類的一種特殊成員函數(shù)。負責將一個類類型的值轉(zhuǎn)換成其他類型。

operator type() const ;

其中 type 表示某種類型。類型轉(zhuǎn)換運算符可以面向任意類型(除了 void 之外)進行定義,只要該類型能作為函數(shù)的返回類型。因此,我們不允許轉(zhuǎn)換成數(shù)組或者函數(shù)類型,但允許轉(zhuǎn)換成指針(包括數(shù)組指針及函數(shù)指針)或者引用類型。

一個類型轉(zhuǎn)換函數(shù)必須是類的成員函數(shù);它不能聲明返回類型,形參列表也必須為空。類型轉(zhuǎn)換函數(shù)通常不應該改變待轉(zhuǎn)換對象的內(nèi)容,因此,應該是const。

運用實例,定義一個簡單的類,令其表示 0~255 之間的一個整數(shù):

構造函數(shù)將算術類型的值轉(zhuǎn)換成 SmallInt 對象,而類型轉(zhuǎn)換運算符將 SmallInt 對象轉(zhuǎn)換成 int:

SmallInt si; si = 4; // 將 4 隱式轉(zhuǎn)換成 SmallInt,然后調(diào)用 SmallInt::operator= si + 3; // 首先將 si 隱式地轉(zhuǎn)換成 int,然后執(zhí)行整數(shù)的加法

盡管編譯器一次只能執(zhí)行一個 我們定義的類型轉(zhuǎn)換(如上面的構造函數(shù)/類型轉(zhuǎn)換運算符),但可以將其搭配 內(nèi)置類型轉(zhuǎn)換(如double可以轉(zhuǎn)換成int) 實現(xiàn)二次轉(zhuǎn)換。

// 內(nèi)置類型轉(zhuǎn)換將 doulbe 實參轉(zhuǎn)換成 int SmallInt si = 3.14; // 調(diào)用 SmallInt(int) 構造函數(shù),然后調(diào)用拷貝構造函數(shù) // SmallInt 的類型轉(zhuǎn)換運算符將 si 轉(zhuǎn)換成 int si + 3.14// 內(nèi)置類型將所得的 int 繼續(xù)轉(zhuǎn)換成 double

盡管類型轉(zhuǎn)換函數(shù)不負責指定返回類型,但實際上每個類型轉(zhuǎn)換函數(shù)都會返回一個對應類型的值:


避免過度使用類型轉(zhuǎn)換函數(shù)

  • 類型轉(zhuǎn)換可能具有誤導性
  • 例如,假設某個類表示 Date,我們也許會為它添加一個從 Date 到 int 的轉(zhuǎn)換。然而,類型轉(zhuǎn)換函數(shù)的返回值應該是什么?

    • 一種可能的解釋是,函數(shù)返回一個十進制數(shù),依次表示年、月、日,例如,July 30,1989 可能轉(zhuǎn)換為 int 值 19890730。
    • 同時還存在另外一種合理的解釋,即類型轉(zhuǎn)換運算符返回的 int 表示的是從某個時間節(jié)點(比如 January 1,1970)開始經(jīng)過的天數(shù)。

    問題在于 Date 類型的對象和 int 類型的值之間不存在明確的一對一映射關系。因此在此例中,不定義該類型轉(zhuǎn)換運算符也許會更好。作為替代的手段,類可以定義一個或多個普通的成員函數(shù)以從各種不同形式中提取所需的信息。

  • 類型轉(zhuǎn)換運算符可能產(chǎn)生意外結果
  • 對于類來說,定義向 bool 的類型轉(zhuǎn)換還是比較普遍的現(xiàn)象。

    int i = 42; cin << i; // 如果向 bool 的類型轉(zhuǎn)換不是顯式的,則該代碼在編譯器看來是合法的

    因為 istream 本身并沒有定義 <<,所以本來代碼應該產(chǎn)生錯誤。然而,該代碼能使用 istream 的 bool類型轉(zhuǎn)換運算符 將 cin 轉(zhuǎn)換成 bool ,而這個 bool值 接著會被提升成 int 并用作內(nèi)置的左移運算符的左側運算對象。這樣一來,提升后的 bool值(1或0) 最終會 被左移42個位置。 這一結果顯然與我們的預期大相徑庭。


    解決上述問題的方法

    轉(zhuǎn)換為 bool

    • 標準庫的早期版本中,IO 類型定義了向 void* 的轉(zhuǎn)換規(guī)則,以求避免上述問題。
    • 在 C++11 標準中,IO 標準庫通過定義一個向 bool 的顯式類型轉(zhuǎn)換實現(xiàn)同樣的目的。

    其實我們在編程中經(jīng)常用到 IO 類型定義的 operator bool :

    while(std::cin >> value)

    為了對條件求值,cin 被 istream operator bool 類型轉(zhuǎn)換函數(shù)隱式地執(zhí)行了轉(zhuǎn)換。如果 cin 的條件狀態(tài)是 good,則該函數(shù)返回為真;否則該函數(shù)返回為假。(這部分知識可以看我之前的博客)

    向 bool 的類型轉(zhuǎn)換通常用在條件部分,因此 operator bool 一般定義成 explicit 的。


    顯式的類型轉(zhuǎn)換運算符

    為了防止上面第二點這樣的異常情況發(fā)生,我們可以使用 explicit 關鍵字。

    SmallInt si = 3; // 正確:SmallInt 的構造函數(shù)不是顯式的 si + 3; // 錯誤:explicit阻止隱式類型轉(zhuǎn)換 static_cast<int>(si) + 3; // 正確:顯式地請求類型轉(zhuǎn)換

    當類型轉(zhuǎn)換運算符是顯式的時,我們也能執(zhí)行類型轉(zhuǎn)換,不過必須通過顯式的強制類型轉(zhuǎn)換才可以。

    該規(guī)定存在一個例外,即,如果表達式被用作條件,則編譯器會將顯式的類型轉(zhuǎn)換自動應用于它。 換句話說,當表達式出現(xiàn)在下列位置時,顯式的類型轉(zhuǎn)換將被隱式地執(zhí)行:

    • if 、while 及 do 語句的條件部分
    • for 語句頭的條件表達式
    • 邏輯非運算符(!)、邏輯或運算符(||)、邏輯與運算符(&&)的運算對象
    • 條件運算符(? :)的條件表達式。

    類型轉(zhuǎn)換二義性

    如果類中包含一個或多個類型轉(zhuǎn)換,則必須確保在類類型和目標類型之間只存在唯一一種轉(zhuǎn)換方式。否則的話,我們編寫的代碼將很可能會具有二義性。

    在兩種情況下可能產(chǎn)生多重轉(zhuǎn)換路徑:

  • 第一種情況是 兩個類提供相同的類型轉(zhuǎn)換: 例如,當 A類 定義了一個接受 B類 對象的轉(zhuǎn)換構造函數(shù),同時 B類 定義了一個轉(zhuǎn)換目標是 A類 的類型轉(zhuǎn)換運算符。
  • 第二種情況是 類定義了多個轉(zhuǎn)換規(guī)則,而某些轉(zhuǎn)換規(guī)則可以通過其他類型轉(zhuǎn)換實現(xiàn)。 這種情況多出現(xiàn)在算術運算符上。
  • 通常情況下,不要為類定義相同的類型轉(zhuǎn)換,也不要在類中定義兩個及兩個以上轉(zhuǎn)換源或轉(zhuǎn)換目標是算術類型的轉(zhuǎn)換。

    第一種情況舉例:

    解決方法是顯式調(diào)用:

    A a1 = f(b.operator A()); A a2 = f(A(b));

    第二種情況舉例:


    我們使用兩個用戶定義的類型轉(zhuǎn)換時,如果轉(zhuǎn)換函數(shù)之前或之后存在標準類型轉(zhuǎn)換,則標準類型轉(zhuǎn)換將決定最佳匹配到底是哪個:

    short s = 42; // 把 short 提升成 int 優(yōu)于 提升成 double // 上面的 long 則沒有int和double誰優(yōu)于誰的規(guī)則,因此會有二義性 A a3(s); // A::A(int)

    重載函數(shù)與類型轉(zhuǎn)換結合導致的二義性

    有時會出現(xiàn)這種情況:

    或這種情況:

    雖然我們可以通過顯式地構造正確的類型而消除二義性:

    manip(C(10)); // 調(diào)用 manip(const C&) manip2(E(double(10))); // 調(diào)用 manip2(const E&)

    但意味著程序的設計存在不足。


    重載運算符與類型轉(zhuǎn)換結合導致的二義性

    重載的運算符也是重載的函數(shù)。因此也遵從通用的函數(shù)匹配規(guī)則。例如,如果 a 是一種類類型,則表達式 a sym b 可能是:

    a.operatorsym(b); // a 有一個 operatorsym 成員函數(shù) operatorsym(a, b); // operatorsym 是一個普通函數(shù)

    和普通函數(shù)不同,我們無法通過調(diào)用的形式區(qū)分當前調(diào)用的是成員函數(shù)還是非成員函數(shù)。

    舉個例子:

    • 第一條加法語句接受兩個 SmallInt 值并執(zhí)行 + 運算符的重載版本。
    • 第二條加法語句具有二義性:因為我們可以把 0 轉(zhuǎn)換成 SmallInt,然后使用 SmallInt 的 +;或者把 s3 轉(zhuǎn)換成 int,然后對于兩個 int 執(zhí)行內(nèi)置的加法運算。

    如果我們對同一個類既提供了轉(zhuǎn)換目標是算術類型的類型轉(zhuǎn)換,也提供了重載的運算符,則將會遇到重載運算符與內(nèi)置運算符的二義性問題。

    總結

    以上是生活随笔為你收集整理的C++ 运算符重载(二) | 类型转换运算符,二义性问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。