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

C++ Primer 第五版 第15章 面向對象程序設計:習題完整解析與代碼實現

     編輯:關於C++

《C++ Primer》第 15 章聚焦繼承、虛函數、多態、抽象基類、訪問控制、類型轉換、動態綁定、虛析構函數、文本查詢系統。本文提供全章習題詳細答案、核心概念解析、關鍵代碼實現(Quote 體系、Basket、Query 系統),並總結工程最佳實踐。

一、核心概念速查表

概念定義/規則
虛函數基類用 virtual 聲明,派生類可覆蓋(override),支持動態綁定。構造函數不能虛,析構函數**應為虛**
純虛函數virtual Ret fun() = 0;,含純虛函數的類為抽象基類,不可實例化
protected派生類成員/友元可訪問,外部不可訪問;比 private 寬鬆,比 public 嚴格
公有繼承建立 is-a 關係,基類接口完整保留,支持向上轉型(多態基礎)
私有/保護繼承建立 has-a / implemented-in-terms-of 關係,基類 public/protected 成員在派生類變為 private/protected,外部不可轉型
虛析構函數確保 delete base_ptr 正確調用派生類析構函數,防止資源洩漏
靜態類型 vs 動態類型靜態:編譯時聲明類型;動態:運行時對象實際類型。指針/引用兩者可能不同
動態綁定條件虛函數 + 基類指針/引用 + 派生類對象
override / finaloverride 明確覆蓋意圖,編譯器檢查簽名匹配;final 禁止進一步覆蓋/繼承
繼承構造函數C++11 using Base::Base; 繼承基類構造函數(除默認/拷貝/移動)

二、Quote 體系:面向對象設計範例

2.1 基類 Quote

class Quote {
public:
    Quote() = default;
    Quote(const string& book, double price) : bookNo(book), price(price) {}
    string isbn() const { return bookNo; }
    virtual double net_price(size_t n) const { return n * price; }
    virtual void debug() const { cout << "bookNo=" << bookNo << " price=" << price << endl; }
    virtual ~Quote() = default; // 虛析構函數!
private:
    string bookNo;
protected:
    double price = 0.0;
};

2.2 折扣基類 Disc_quote(抽象)

class Disc_quote : public Quote {
public:
    Disc_quote() = default;
    Disc_quote(const string& book, double price, size_t qty, double disc)
        : Quote(book, price), quantity(qty), discount(disc) {}
    double net_price(size_t) const = 0; // 純虛函數
protected:
    size_t quantity = 0;
    double discount = 0.0;
};

2.3 批量折扣 Bulk_quote

class Bulk_quote : public Disc_quote {
public:
    using Disc_quote::Disc_quote; // 繼承構造函數
    double net_price(size_t cnt) const override {
        if (cnt >= quantity) return cnt * (1 - discount) * price;
        else return cnt * price;
    }
    void debug() const override {
        Quote::debug();
        cout << "quantity=" << quantity << " discount=" << discount << endl;
    }
};

2.4 限量折扣 Limited_quote(習題 15.7/16)

class Limited_quote : public Disc_quote {
public:
    using Disc_quote::Disc_quote;
    double net_price(size_t cnt) const override {
        if (cnt <= quantity) return cnt * (1 - discount) * price;
        else return quantity * (1 - discount) * price + (cnt - quantity) * price;
    }
};

三、動態綁定與多態實戰

3.1 print_total 函數

double print_total(ostream& os, const Quote& item, size_t n) {
    double ret = item.net_price(n); // 動態綁定:實際調用派生類版本
    os << "ISBN: " << item.isbn() << " #sold: " << n << " total due: " << ret << endl;
    return ret;
}

3.2 容器存儲策略對比

策略代碼行為適用場景
對象切片vector vec; vec.push_back(bulk);僅保留基類部分,**靜態綁定**調用 Quote::net_price錯誤用法,切片丟失派生類狀態
裸指針vector vec; vec.push_back(&bulk);動態綁定,但**手動管理生命周期**,易洩漏/懸空避免使用
智能指針vector> vec; vec.push_back(make_shared(...));動態綁定 + 自動生命周期管理,推薦標準做法生產代碼首選

四、Basket 購物籃系統(習題 15.30)

class Basket {
public:
    void add_item(const shared_ptr& sale) { items.insert(sale); }
    double total_receipt(ostream& os) const {
        double sum = 0.0;
        for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter)) {
            sum += print_total(os, **iter, items.count(*iter));
        }
        os << "Total Sale: " << sum << endl;
        return sum;
    }
private:
    static bool compare(const shared_ptr& lhs, const shared_ptr& rhs) {
        return lhs->isbn() < rhs->isbn();
    }
    multiset, decltype(compare)*> items{compare};
};

五、文本查詢系統:Query 類層次(習題 15.31-42)

5.1 核心類圖

Query_base (抽象)
  ├─ WordQuery          // 單詞查詢
  ├─ NotQuery           // ~Query
  ├─ BinaryQuery (抽象) // 兩操作數
  │    ├─ AndQuery      // Query & Query
  │    └─ OrQuery       // Query | Query
Query (句柄類)          // 封裝 shared_ptr,提供運算符重載、eval、rep

5.2 關鍵實現片段

// Query 句柄類
class Query {
    friend Query operator~(const Query&);
    friend Query operator|(const Query&, const Query&);
    friend Query operator&(const Query&, const Query&);
public:
    Query(const string& s) : q(new WordQuery(s)) {}
    QueryResult eval(const TextQuery& t) const { return q->eval(t); }
    string rep() const { return q->rep(); }
private:
    Query(shared_ptr query) : q(query) {}
    shared_ptr q;
};

// 二元查詢基類
class BinaryQuery : public Query_base {
protected:
    BinaryQuery(const Query& l, const Query& r, string op)
        : lhs(l), rhs(r), oper(op) {}
    string rep() const override { return "(" + lhs.rep() + " " + oper + " " + rhs.rep() + ")"; }
    Query lhs, rhs;
    string oper;
};

// AndQuery / OrQuery 繼承 BinaryQuery,實現 eval() 進行 set_intersection / set_union
// NotQuery 實現 eval() 進行 set_difference (全行集 - 子查詢結果)

5.3 表達式構建對象數量分析(習題 15.31)

表達式創建對象數構成
Query(s1) | Query(s2) & ~Query(s3)12 個3 WordQuery + 1 NotQuery + 1 AndQuery + 1 OrQuery + 6 Query 句柄
Query(s1) | (Query(s2) & ~Query(s3))12 個同上,結合性不影響對象數
(Query(s1) & Query(s2)) | (Query(s3) & Query(s4))14 個4 WordQuery + 2 AndQuery + 1 OrQuery + 7 Query 句柄

六、習題精選答案摘要

題號考點答案要點
15.1虛成員定義基類希望派生類重定義的非 static 成員(除構造函數外)
15.2protected vs privateprotected 允許派生類訪問,private 不允許
15.3Quote/print_total 定義見 2.1、3.1
15.4派生列表合法性(a) 錯誤:類不能繼承自己 (b) 合法 (c) 錯誤:前向聲明不可含派生列表
15.5Bulk_quote 定義見 2.3
15.7限量折扣策略見 2.4
15.8靜態/動態類型定義靜態:編譯時類型;動態:運行時對象類型
15.9類型不一致場景基類指針/引用指向派生類對象:Quote* p = new Bulk_quote; Quote& r = bulk;
15.11虛 debug 函數基類定義 virtual debug(),派生類 override 並調用基類版本
15.12override + final 必要性必要:override 防止簽名錯誤,final 防止進一步覆蓋,意圖明確
15.14虛函數調用解析對象調用→靜態綁定;指針/引用調用→動態綁定(運行時類型決定)
15.15Disc_quote 抽象基類見 2.2
15.18繼承方式與向上轉型僅公有繼承允許用戶代碼隱式向上轉型
15.19派生類成員函數轉型合法性私有繼承體系中,派生類成員函數**不能**將 *this 轉為基類引用(對用戶代碼不可見,但對成員可見)
15.22幾何圖元繼承體系設計Figure → Figure_2D(area/perimeter) → Rectangle/Circle; Figure_3D(cubage) → Sphere/Cone
15.24虛析構函數必要性基類指針刪除派生類對象時正確調用派生類析構函數
15.25Disc_quote 默認構造函數作用初始化基類 Quote 部分,缺失將導致 Bulk_quote 默認構造失敗
15.26拷貝控制成員實現合成版本行為:拷貝 shared_ptr 計數+1,移動轉移所有權
15.27繼承構造函數using Disc_quote::Disc_quote;
15.28-29容器存儲策略差異對象切片調用基類版本;shared_ptr 調用派生類版本(動態綁定)
15.32-33Query/Query_base 拷貝語義Query 合成拷貝控制(shared_ptr 語義);Query_base 無數據成員,合成版本無操作
15.35Query/Query_base 核心定義見 5.2
15.38聲明合法性BinaryQuery 抽象不可實例化;Query 不能隱式轉為 AndQuery/OrQuery
15.40OrQuery 空集處理set 構造/插入天然支持空範圍,結果正確
15.41原始指針實現 Query需手動引用計數(uc),實現拷貝/賦值/析構,極易出錯,**不推薦**
15.42擴展設計(a) 按句子索引 (b) 歷史系統 (c) 結果範圍限制

七、工程最佳實踐總結

  1. 公有繼承表達 is-a,組合優於繼承(has-a)
  2. 基類析構函數必須虛,防止資源洩漏
  3. 虛函數盡量加 override,葉子類加 final
  4. 多態容器統一用 shared_ptr,避免切片與手動內存管理
  5. 抽象基類定義接口,具體類實現細節,依賴倒置原則
  6. 類型轉換運算符與單參數構造函數加 explicit,避免隱式轉換陷阱
  7. 文本查詢系統展示了「句柄/主體」模式:Query 輕量句柄,Query_base 體系承擔邏輯,運算符重載構建領域語言

第 15 章是 C++ 面向對象精髓所在,徹底掌握繼承體系設計、動態綁定機制、資源管理規範,是編寫大型可維護 C++ 系統的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved