C++基礎——類繼承中方法重載

来源:https://www.cnblogs.com/moluoqishi/archive/2019/04/21/10746046.html
-Advertisement-
Play Games

一、前言 在上一篇C++基礎博文中討論了C++最基本的代碼重用特性——類繼承,派生類可以在繼承基類元素的同時,添加新的成員和方法。但是沒有考慮一種情況:派生類繼承下來的方法的實現細節並不一定適合派生類的需求,此時派生類需要重載集成方法。 二、重載方法及虛函數 我們討論《C++ Primer Plus ...


一、前言

       在上一篇C++基礎博文中討論了C++最基本的代碼重用特性——類繼承,派生類可以在繼承基類元素的同時,添加新的成員和方法。但是沒有考慮一種情況:派生類繼承下來的方法的實現細節並不一定適合派生類的需求,此時派生類需要重載集成方法。

二、重載方法及虛函數

    我們討論《C++ Primer Plus》中的如下場景:銀行記錄客戶信息,包括客戶姓名、當前餘額。客戶這一類別當然能夠創建客戶對象、存款、取款以及顯示信息。銀行需要特殊記錄具有透支許可權的客戶,因此這一類別的客戶要額外記錄透支上限、透支貸款利率以及當前透支總額。此外,取款和顯示信息兩個操作必須考慮客戶的透支情況。綜上,具有透支許可權的客戶是客戶這一基類的派生類,派生類中不但需要添加新的成員,還要重載兩個繼承方法。

  類聲明代碼:

 1 #ifndef BRASS_H_
 2 #define BRASS_H_
 3 
 4 #include <string>
 5 
 6 class Brass
 7 {
 8 private:
 9     std::string fullName;
10     long acctNum;
11     double balance;
12 public:
13     Brass(const std::string& s = "Nullbody",long an = -1,double ba = 0.0);//default constructor
14     void Deposit(double amt);
15     double Balance() const;
16     virtual void Withdraw(double amt);//virtual function
17     virtual void ViewAcct() const;
18     virtual ~Brass() {}//使用虛析構函數確保先調用繼承類析構函數
19 };
20 
21 //brass plus account class
22 class BrassPlus:public Brass
23 {
24 private:
25     double maxLoan;
26     double rate;
27     double owesBank;
28 public:
29     BrassPlus(const std::string& s = "Nullbody",long an = -1,
30                 double bal = 0.0,double ml = 500,double r = 0.11125);
31     BrassPlus(const Brass& ba,double ml = 500,double r = 0.11125);
32     virtual void ViewAcct() const;
33     virtual void Withdraw(double amt);
34     void ResetMax(double m) {maxLoan = m;}//inline function
35     void ResetRate(double r) {rate = r;}
36     void ResetOwes() {owesBank = 0;}
37 };
38 
39 #endif
brass.h

  類方法定義代碼:

 1 #include"brass.h"
 2 #include <iostream>
 3 
 4 using std::cout;
 5 using std::endl;
 6 using std::string;
 7 
 8 //brass methods
 9 Brass::Brass(const string& s,long an,double bal)
10 {
11     fullName = s;
12     acctNum = an;
13     balance = bal;
14 }
15 
16 void Brass::Deposit(double amt)
17 {
18     if(amt < 0)
19         cout << "Negative deposit not allowed;"
20             << "deposit is cancelled.\n";
21     else
22         balance += amt;
23 }
24 
25 void Brass::Withdraw(double amt)
26 {
27     if(amt < 0)
28         cout << "Withdrawal amount must be positive;"
29             << "withdrawal canceled.\n";
30     else if (amt <= balance)
31         balance -= amt;
32     else
33         cout << "Withdrawal amount of $" << amt 
34             << "exceeds your balance.\n"
35             << "Withdrawal canceled.\n";
36 }
37 
38 double Brass::Balance() const
39 {
40     return balance;
41 }
42 
43 void Brass::ViewAcct() const
44 {
45     cout << "Client: " << fullName << endl;
46     cout << "Account Number: " << acctNum << endl;
47     cout << "Balance: $" << balance << endl;
48 }
49 
50 //brassPlus methods
51 BrassPlus::BrassPlus(const string& s,long an,double bal,
52                      double ml,double r):Brass(s,an,bal)
53 {
54     maxLoan = ml;
55     owesBank = 0.0;
56     rate = r;
57 }
58 
59 BrassPlus::BrassPlus(const Brass& ba,double ml,double r):Brass(ba)
60 {
61     maxLoan = ml;
62     owesBank = 0.0;
63     rate = r;
64 }
65 
66 //redefine viewacct()
67 void BrassPlus::ViewAcct() const
68 {
69     Brass::ViewAcct();
70     cout << "Maximum loan: $" << maxLoan << endl;
71     cout << "Owed to bank: $" << owesBank << endl;
72 }
73 
74 void BrassPlus::Withdraw(double amt)
75 {
76     double bal = Balance();
77     if(amt <= bal)
78         Brass::Withdraw(amt);
79     else if(amt <= bal + maxLoan - owesBank)// 已欠 + 此欠 ≤ maxLoan
80     {
81         double advance = amt - bal;
82         owesBank += advance * (1.0+rate);
83         cout << "Bank advance: $" << advance << endl;
84         cout << "Finance charge: $" << advance*rate << endl;
85         Deposit(advance);
86         Brass::Withdraw(amt);// return to zero
87     }
88     else
89         cout << "Credit limit exceeded. Transcation cancelled.\n" ;
90 }
brass.cpp

   上述代碼多了一個新的語法特性:虛函數(virtual function)。當基類聲明中函數前加virtual,表示該函數為虛函數。區別在於當調用者是引用或者指針時,調用的是基類方法,還是派生類重載後的方法。具體區別我們後邊在討論。重中之重在於虛析構函數的意義。如果程式中使用delete刪除占用的動態記憶體,且用於索引記憶體地址的指針類型是基類,那麼即使該指針指向的是一個派生類對象,此時僅基類析構函數被調用。 我們著重觀察brassPlus類重載的方法WithDraw有什麼變化。這類客戶由於具有透支許可權,在取款時肯定要考慮欠款情況。若欲取出金額≤存儲金額,則直接調用基類方法WithDraw,把存儲金額減小;若欲取出金額大於存儲金額,就必須進一步分析欠款情況。已欠款+此次欠款≤透支額度時,取款操作才有效。因此:owes+(amt - balance) ≤ maxLoan,進一步變形為:amt ≤ balance+maxLoan-owes。

三、應用程式示例及結果分析

 現在看看應用程式代碼和顯示結果。APP代碼:

 1 #include <iostream>
 2 #include "brass.h"
 3 
 4 int main()
 5 {
 6     using std::cout;
 7     using std::endl;
 8 
 9     Brass Piggy("Porcelot Pigg",381299,4000.00);
10     BrassPlus Hoggy("Horatio Hogg",382288,3000.00);
11 
12     Piggy.ViewAcct();
13     cout << endl;
14     Hoggy.ViewAcct();
15     cout << endl;
16     
17     cout << "Depositing $1000 into the Hogg Account:\n";
18     Hoggy.Deposit(1000.00);
19     cout << "New balance: $" <<Hoggy.Balance() <<endl;
20     cout << endl;
21 
22     cout << "Withdrawing $4200 from the Pigg Account:\n";
23     Piggy.Withdraw(4200.00);
24     cout << "Pigg account balance: $" << Piggy.Balance() << endl;
25     cout << endl;
26     
27     cout << "Withdrawing $4200 from the Hogg Account:\n";
28     Hoggy.Withdraw(4200.00);
29     Hoggy.ViewAcct();
30     cout << endl;
31 
32     Brass dom("Dominic Banker",11224,4183.45);
33     BrassPlus dot("Dorothy Banker",12118,2592.00);
34 
35     Brass& b1_ref = dom;
36     Brass& b2_ref = dot;//use BrassPlus::ViewAcct() function
37 
38     b1_ref.ViewAcct();
39     cout << endl;
40     b2_ref.ViewAcct();
41     cout << endl;
42 
43     return 0;
44 }
usebrass.cpp

  列印結果:

   Pigg和Hogg分別是基類和派生類對象。當兩種均取款額度超出存儲金額時,Hogg由於具有透支許可權,才得以成功完成操作。註意之後創建的兩個對象dom和dot,從調用ViewAcct()函數過程中再次體會虛函數的意義。若沒有使用virtual關鍵字,程式根據引用或指針的類型選擇使用基類方法還是派生類同名的重載後方法。若使用該關鍵字,則根據引用或指針所指向對象的類型來選擇。程式中,b1_ref和b2_ref均是Brass類引用,但分別是Brass類對象dom和BrassPlus類對象dot的別名,因此使用virtual關鍵字後的ViewAcct()函數,依次調用基類和派生類方法。收工。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 游戲功能和流程圖 實現功能:翻開兩個一樣的牌子就顯示,全部翻開游戲結束,設置5種圖形,7種顏色,游戲開始提示隨機8個牌子 游戲流程圖 2. 游戲配置 配置游戲目錄 配置游戲(game_conf.py) 配置顏色(color.py) 配置形狀(shape.py) 3. 游戲使用工具函數(view ...
  • 1.當前路徑及路徑下的文件 os.getcwd():查看當前所在路徑。 os.listdir(path):列舉目錄下的所有文件。返回的是列表類型。 2.os.path.splitext(path) 分離文件名與擴展名;預設返回(fname,fextension)元組,可做分片操作 >>> os.pa ...
  • 如 "abcdt" 反轉之後是 "tdcba" 思路1: 運用遞歸的方法進行反轉 假設反轉方法為 reverseString(String str)1)當字元串為空或者只有一個字元時,返回原字元2)當字元串有兩個以上(長度為len)的字元時,反轉後的字元串為 第二個字元開始的子串的反轉結果+第一個字 ...
  • 內置函數是 Python 的一大特色,用極簡的語法實現很多常用的操作。 它們預先定義在內置命名空間中,開箱即用,所見即所得。Python 被公認是一種新手友好型的語言,這種說法能夠成立,內置函數在其中起到了極關鍵的作用。 舉個例子,求字元串 x 的長度,Python 的寫法是 len(x) ,而且這 ...
  • 一、流的概念 流:數據在數據源(文件)和程式(記憶體)之間經歷的路徑。 輸入流:數據從數據源(文件)到程式(記憶體)的路徑。 輸出流:數據從程式(記憶體)到數據源(文件)的路徑。 以記憶體為參照,如果數據向記憶體流動,則是輸入流,反之則是輸出流 位元組流:FileInputStream用來讀取文件 FileOu ...
  • 選擇排序:是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完。 原理:首先用第一個元素和後面的每一個元素進行比較,如果後面有比第一個元素小的就交換這兩個元素 比較下來會得到第最小的一個元素,放在第一個位置,然後依次拿著後面每一個元素依次這樣比 ...
  • 概述 由於Go語言不允許隱式類型轉換,不同的類型之間的轉換必須做顯示的類型轉換。而類型轉換和類型斷言的本質,就是把一個類型轉換到另一個類型。 不過Go語言必須做顯示的類型轉換的要求也有例外的情況: 當普通 T 類型變數向 I 介面類型轉換時,是隱式轉換的(編譯時轉換);(T->I) 當 IX 介面變 ...
  • 冒泡排序演算法的原理如下:1.比較相鄰的元素。如果第一個比第二個大,就交換他們兩個,否則不交換2.對每一對相鄰元素做同樣的工作,從開始第一對到結尾的最後一對。做完這一步,最後的元素應該會是最大的數。3.針對所有的元素重覆以上的步驟,除了最後一個。4.持續每次對越來越少的元素重覆上面的步驟,直到沒有任何 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...