首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ Primer 第14章習題精解:運算符重載、類型轉換與函數對象全攻略

     編輯:關於C++

C++ Primer 第14章聚焦運算符重載與類型轉換,本文精選典型習題,從輸入輸出運算符、算術/關係運算符、賦值/下標/調用運算符到類型轉換運算符、lambda與函數對象,提供標準答案與核心解析,助你掌握類設計精髓。

核心知識點速覽

運算符類別建議形式關鍵規則
輸入/輸出 << >>非成員友元左操作數為流對象,不可為成員
算術 + - * /非成員利用復合賦值 += 實現,保證對稱性
復合賦值 += -=成員修改左操作數狀態,返回 *this
關係 == <非成員支持隱式轉換,符合直覺
賦值 =成員處理自賦值,釋放舊資源,深拷貝
下標 []成員提供 const 非 const 兩版本
遞增/遞減 ++ --成員前綴返回引用,後綴返回舊值副本
解引用 * 箭頭 ->成員智能指針/迭代器必備
函數調用 ()成員實現函數對象,可保存狀態
類型轉換成員單參數構造函數配合 explicit 控制隱式轉換

精選習題解析

14.1-14.4:運算符重載基礎規則

  • 重載 vs 內置:重載至少一個類類型操作數;&& || 重載失去短路求值;優先級/結合性/操作數個數不變。
  • 成員 vs 非成員:= () [] -> 必須為成員;<< >> == + 建議非成員;修改狀態的(+= ++)為成員。

14.5-14.8:輸出運算符實戰

// Date 類輸出運算符
ostream& operator<<(ostream& os, const Date& d) {
    return os << "year:" << d.year << '\t' << "month:" << d.month << '\t' << "day:" << d.day << endl;
}

// Sales_data 輸出
ostream& operator<<(ostream& os, const Sales_data& item) {
    return os << item.isbn() << ' ' << item.units_sold << ' ' << item.revenue;
}

14.10-14.12:輸入運算符與錯誤處理

輸入運算符必須檢查流狀態,失敗時將對象置為默認狀態:

istream& operator>>(istream& is, Date& dt) {
    is >> dt.year >> dt.month >> dt.day;
    if (!is) dt = Date(0,0,0); // 輸入失敗重置
    return is;
}

14.13-14.21:算術運算符設計模式

標準模式:operator+ 調用 operator+=,避免代碼重複,性能無損(RVO優化):

Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs) {
    Sales_data sum = lhs; sum += rhs; return sum;
}
Sales_data& Sales_data::operator+=(const Sales_data& rhs) {
    units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;
}

反模式:+= 調用 + 會創建臨時對象,效率低、可讀性差。

14.22-14.25:賦值運算符變體

  • Sales_data& operator=(const string& isbn):支持 ISBN 字符串直接賦值。
  • StrVec& operator=(initializer_list<string>):支持列表初始化賦值。
  • 若類僅含內置類型成員(如 Date),默認拷貝/移動賦值足夠,無需自定義。

14.26-14.32:下標、遞增、指針運算

// StrBlob 下標
string& operator[](size_t n) { return data[n]; }
const string& operator[](size_t n) const { return data[n]; }

// StrBlobPtr 遞增/遞減(前綴/後綴)
StrBlobPtr& operator++() { check(curr, "increment past end"); ++curr; return *this; }
StrBlobPtr operator++(int) { StrBlobPtr ret = *this; ++*this; return ret; }

// 指針算術
StrBlobPtr operator+(int n) { StrBlobPtr ret = *this; ret.curr += n; return ret; }

14.33-14.41:函數對象與 Lambda

  • operator() 可接受任意數量參數(含0個)。
  • Lambda vs 函數對象:Lambda 適合一次性簡單邏輯;函數對象適合需保存狀態、多處復用的場景。
  • 標準庫適配器:bind2nd、not_equal_to、greater 等配合算法使用。

14.42-14.44:標準庫函數對象實戰


// 統計 >1024 的個數
count_if(vec.begin(), vec.end(), bind2nd(greater(), 1024));
// 找第一個不等於 "pooh" 的字符串
find_if(vec.begin(), vec.end(), bind2nd(not_equal_to(), "pooh"));
// 所有值乘2
transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies(), 2));

14.45-14.53:類型轉換運算符與二義性

  • explicit operator bool() 防止意外隱式轉換,僅用於條件判斷。
  • 轉換函數不指定返回類型,如 operator int()。
  • 二義性陷阱:多條隱式轉換路徑導致編譯錯誤,需顯式轉型消除。

最佳實踐清單

  1. 輸入輸出運算符定義為非成員友元。
  2. 算術運算符以復合賦值為基礎實現。
  3. 關係運算符定義為非成員,支持對稱比較。
  4. 賦值運算符檢查自賦值,強異常安全。
  5. 下標運算符提供 const/非 const 重載。
  6. 遞增遞減:前綴返回引用,後綴返回值。
  7. 類型轉換運算符盡量 explicit,避免驚喜轉換。
  8. 函數對象用於有狀態邏輯,Lambda 用於臨時簡單邏輯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved