C++Primer Plus笔记——第十三章 类继承总结及程序清单
发布日期:2021-06-29 01:51:03 浏览次数:2 分类:技术文章

本文共 17402 字,大约阅读时间需要 58 分钟。

目录


本章小结

       继承通过使用已有的类(基类)定义新的类(派生类),使得能够根据需要修改编程代码。公有继承建立is-a关系,这意味若派生类对象也应该是某种基类对象。作为is-a模型的一部分,派生类继承基类的数据成员和大部分方法,但不继承基类的构造函数、析构函数和赋值运算符。派生类可以直接访问基类的公有成员和保护成员,并能够通过基类的公有方法和保护方法访问基类的私有成员。可以在派化类中新增数据成员和方法,还可以将派生类用作基类,来做进一步的开发。每个派生类都必须有自己的构造函数。程序创建派生类对象时,将首先调用基类的构造函数,然后调用派生类的构造函数;程序删除对象时,将首先调用派生类的析构函数,然后调用基类的析构函数。

       如果要将类用作基类,则可以将成员声明为保护的,而不是私有的,这样,派生类将可以直接访问这些成员。然而,使用私有成员通常可以减少出现编程问题的可能性。如果希望派生类可以重新定义基类的方法,则可以使用关键字virtual将它声明为虚的。这样对于通过指针或引用访问的对象,能够根据对象类型来处理,而不是根据引用或指针的类型来处理。具体地说,基类的析构函数通常应当是虚的。

       可以考虑定义一个ABC:只定义接口,而不涉及实现。例如,可以定义抽象类Shape,然后使用它派生出具体的形状类,如Circle和Square。ABC必须至少包含一个纯虚方法,可以在声明中的分号前面加h=0 来声明纯虚方法,

       virtual double area{} const = 0;

       不一定非得定义纯虚方法。对于包含纯虚成员的类,不能使用它来创建对象。纯虚方法用于定义派生类的通用接口。

程序清单

一个简单的基类

13.1 tabtenn0.h

//tabtenn0.h -- a table-tennis base class#ifndef TABTENN0_H_#define TABTENN0_H_#include 
using std::string;class TableTennisPlayer{private: string firstname; string lastname; bool hasTable;public: TableTennisPlayer(const string & fn = "none", const string & ln = "none", bool ht = false); void Name() const; bool HasTable() const { return hasTable; } void ResetTable(bool v) { hasTable = v; }};#endif // !TABTENN0_H_

13.2 tabtenn0.cpp

//tabtenn0.cpp -- simple base-class methods#include 
#include "tabtenn0.h"TableTennisPlayer::TableTennisPlayer(const string & fn, const string & ln , bool ht):firstname(fn),lastname(ln),hasTable(ht) {}void TableTennisPlayer::Name() const{ std::cout << lastname << ", " << firstname;}

13.3 usett0.cpp

//usett0.cpp -- using a base class#include 
#include "tabtenn0.h"int main(){ using namespace std; TableTennisPlayer player1("Chuck", "Blizzard", true); TableTennisPlayer player2("Tara", "Boomdea", false); player1.Name(); if (player1.HasTable()) cout << ": has a table.\n"; else cout << ": hasn't a table.\n"; player2.Name(); if (player2.HasTable()) cout << ": has a table.\n"; else cout << ": hasn't a table.\n"; return 0;}

派生一个类

13.4 tabtenn1.h

//tabtenn1.h -- a table-tennis base class#ifndef TABTENN1_H_#define TABTENN1_H_#include 
using std::string;class TableTennisPlayer{private: string firstname; string lastname; bool hasTable;public: TableTennisPlayer(const string & fn = "none", const string & ln = "none", bool ht = false); void Name() const; bool HasTable() const { return hasTable; } void ResetTable(bool v) { hasTable = v; }};class RatedPlayer :public TableTennisPlayer{private: unsigned int rating;public: RatedPlayer(unsigned int r = 0, const string & fn = "none", const string & ln = "none", bool ht = false); RatedPlayer(unsigned int r, const TableTennisPlayer & tp); unsigned int Rating() const { return rating; } void ResetRating(unsigned int r) { rating = r; }};#endif // !TABTENN0_H_

13.5 tabtenn1.cpp

//tabtenn1.cpp -- simple base-class methods#include 
#include "tabtenn1.h"TableTennisPlayer::TableTennisPlayer(const string & fn, const string & ln, bool ht) :firstname(fn), lastname(ln), hasTable(ht) {}void TableTennisPlayer::Name() const{ std::cout << lastname << ", " << firstname;}RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht) :TableTennisPlayer(fn, ln, ht){ rating = r;}RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp):TableTennisPlayer(tp),rating(r) {}

13.6 usett.cpp

//usett1.cpp -- using a base class and derived class#include 
#include "tabtenn1.h"int main(){ using namespace std; TableTennisPlayer player1("Tara", "Boomdea", false); RatedPlayer rplayer1(1140, "Mallory", "Duck", true); rplayer1.Name(); if (player1.HasTable()) cout << ": has a table.\n"; else cout << ": hasn't a table.\n"; player1.Name(); if (player1.HasTable()) cout << ": has a table.\n"; else cout << ": hasn't a table.\n"; cout << "Name: "; rplayer1.Name(); cout << ": Rating: " << rplayer1.Rating() << endl; RatedPlayer rplayer2(1212, player1); cout << "Name: "; rplayer2.Name(); cout << "; Rating: " << rplayer2.Rating() << endl; return 0;}

多态公有继承

13.7  brass.h

//brass.h -- bank account classes#ifndef BRASS_H_#define BRASS_H_#include 
using namespace std;class Brass{private: string fullName; long acctNum; double balance;public: Brass(const string & s = "Nullbody", long an = -1, double bal = 0.0); void Deposit(double amt); virtual void Withdraw(double amt); double Balance() const; virtual void ViewAcct() const; virtual ~Brass() {}};class BrassPlus :public Brass{private: double maxLoan; double rate; double owesBank;public: BrassPlus(const string & s = "Nullbody", long an = -1, double bal = 0.0, double ml = 500, double r = 0.11125); BrassPlus(const Brass & ba, double ml = 500, double r = 0.11125); virtual void ViewAcct()const; virtual void Withdraw(double amt); void ResetMax(double m) { maxLoan = m; } void ResetRate(double r) { rate = r; } void ResetOwes() { owesBank = 0; }};#endif // !BRASS_H_

13.8 brass.cpp

//brass.cpp -- bank account class methods#include 
#include "brass.h"using namespace std;typedef ios_base::fmtflags format;typedef streamsize precis;format setFormat();void restore(format fm, precis p);Brass::Brass(const string & s /* = "Nullbody" */, long an /* = -1 */, double bal /* = 0.0 */){ fullName = s; acctNum = an; balance = bal;}void Brass::Deposit(double amt){ if (amt < 0) cout << "Negative deposit not allowed; deposit is cancelled:\n"; else balance += amt;}void Brass::Withdraw(double amt){ format initialState = setFormat(); precis prec = cout.precision(2); if (amt < 0) cout << "Withdrawal amout must be positive; withdrawal canceled.\n"; else if (amt <= balance) balance -= amt; else cout << "Withdrawal amount of $" << amt << " exceeds your balance.\n" << "Withdrawal canceled.\n"; restore(initialState, prec);}double Brass::Balance() const{ return balance;}void Brass::ViewAcct() const{ format initialState = setFormat(); precis prec = cout.precision(2); cout << "Client: " << fullName << endl; cout << "Account Number: " << acctNum << endl; cout << "Balance: $" << balance << endl; restore(initialState, prec);}BrassPlus::BrassPlus(const string & s, long an, double bal, double ml, double r) :Brass(s, an, bal){ maxLoan = ml; owesBank = 0.0; rate = r;}void BrassPlus::ViewAcct() const { format initialState = setFormat(); precis prec = cout.precision(2); Brass::ViewAcct(); cout << "Maximum loan: $" << maxLoan << endl; cout << "Owed to bank: $" << owesBank << endl; cout.precision(3); cout << "Loan Rate: " << 100 * rate << "%\n"; restore(initialState, prec);}void BrassPlus::Withdraw(double amt){ format initialState = setFormat(); precis prec = cout.precision(2); double bal = Balance(); if (amt <= bal) Brass::Withdraw(amt); else if (amt <= bal + maxLoan - owesBank) { double advance = amt - bal; owesBank += advance * (1.0 + rate); cout << "Bank advance: $" << advance << endl; cout << "Finance charge: $" << advance * rate << endl; Deposit(advance); Brass::Withdraw(amt); } else cout << "Credit limit exceeded. Transaction cancelled.\n"; restore(initialState, prec);}format setFormat(){ return cout.setf(ios_base::fixed, ios_base::floatfield);}void restore(format f, precis p){ cout.setf(f, ios_base::floatfield); cout.precision(p);}

13.9 usebrass1.cpp 没有使用虚方法特性

//usebrass1.cpp -- testing bank account classes//compile with brass.cpp#include 
#include "brass.h"int main(){ using namespace std; Brass Piggy("Porcelot Pigg", 381299, 4000.00); BrassPlus Hoggy("Horatio Hogg", 382288, 3000.00); Piggy.ViewAcct(); cout << endl; Hoggy.ViewAcct(); cout << endl; cout << "Depositing $1000 into the hogg Account:\n"; Hoggy.Deposit(1000.00); cout << "New balance: $" << Hoggy.Balance() << endl; cout << "Withdrawing $4200 from the Pigg Account:\n"; Piggy.Withdraw(4200.00); cout << "Pigg account balance: $" << Piggy.Balance() << endl; cout << "Withdrawing $4200 from the Hogg Account:\n"; Hoggy.Withdraw(4200.00); Hoggy.ViewAcct(); return 0;}

13.10 usebrass2.cpp 使用虚方法特性

//usebrass2.cpp -- polymorphic example//compile with brass.cpp#include 
#include
#include "brass.h"const int CLIENTS = 4;int main(){ using namespace std; Brass * p_clients[CLIENTS]; string temp; long tempnum; double tempbal; char kind; for (int i = 0; i < CLIENTS; i++) { cout << "Enter client's name: "; getline(cin, temp); cout << "Enter client's account number: "; cin >> tempnum; cout << "Enter opening balance: $"; cin >> tempbal; cout << "Enter 1 for Brass Account or 2 for BrassPlus Account: "; while (cin >> kind && (kind != '1' && kind != '2')) cout << "Enter either 1 or 2:"; if (kind == '1') p_clients[i] = new Brass(temp, tempnum, tempbal); else { double tmax, trate; cout << "Enter the overdraft limit: $"; cin >> tmax; cout << "Enter the interest rate as a decimal fraction: "; cin >> trate; p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate); } while (cin.get() != '\n') continue; } cout << endl; for (int i = 0; i < CLIENTS; i++) { p_clients[i]->ViewAcct(); cout << endl; } for (int i = 0; i < CLIENTS; i++) { delete p_clients[i]; } cout << "Done.\n"; return 0;}

抽象基类

13.11 acctabc.h

//acctabc.h -- bank account classes#ifndef ACCTABC_H_#define ACCTABC_H_#include 
#include
using namespace std;class AcctABC{private: string fullName; long acctNum; double balance;protected: struct Formatting { ios_base::fmtflags flag; streamsize pr; }; const string & FullName() const { return fullName; } long AcctNum() const { return acctNum; } Formatting SetFormat() const; void Restore(Formatting & f) const;public: AcctABC(const string & s = "Nullbody", long an = -1, double baF = 0.0); void Deposit(double amt); virtual void Withdraw(double amt) = 0; double Balance() const { return balance; } virtual void ViewAcct() const = 0; virtual ~AcctABC() {}};class Brass :public AcctABC{public: Brass(const string & s = "Nullbody", long an = -1, double bal = 0.0) :AcctABC(s, an, bal) {} virtual void ViewAcct()const; virtual void Withdraw(double amt); virtual ~Brass() {}};class BrassPlus :public AcctABC{private: double maxLoan; double rate; double owesBank;public: BrassPlus(const string & s = "Nullbody", long an = -1, double bal = 0.0, double ml = 500, double r = 0.10); BrassPlus(const Brass & ba, double ml = 500, double r = 0.10); virtual void ViewAcct()const; virtual void Withdraw(double amt); void ResetMax(double m) { maxLoan = m; } void ResetRate(double r) { rate = r; } void ResetOwes() { owesBank = 0; }};#endif // !ACCTABC_H_

13.12 acctabc.cpp

//acctabc.cpp -- bank account class methods#include 
#include "acctabc.h"using namespace std;AcctABC::AcctABC(const string & s /* = "Nullbody" */, long an /* = -1 */, double bal /* = 0.0 */){ fullName = s; acctNum = an; balance = bal;}void AcctABC::Deposit(double amt){ if (amt < 0) cout << "Negative deposit not allowed; deposit is cancelled:\n"; else balance += amt;}void AcctABC::Withdraw(double amt){ balance -= amt;}AcctABC::Formatting AcctABC::SetFormat() const{ Formatting f; f.flag = cout.setf(ios_base::fixed, ios_base::floatfield); f.pr = cout.precision(2); return f;}void AcctABC::Restore(Formatting & f) const{ cout.setf(f.flag, ios_base::floatfield); cout.precision(f.pr);}void Brass::Withdraw(double amt){ if (amt < 0) cout << "Withdrawal amout must be positive; withdrawal canceled.\n"; else if (amt <= Balance()) AcctABC::Withdraw(amt); else cout << "Withdrawal amount of $" << amt << " exceeds your balance.\n" << "Withdrawal canceled.\n";}void Brass::ViewAcct() const{ Formatting f = SetFormat(); cout << "Brass Client: " << FullName() << endl; cout << "Account Number: " << AcctNum() << endl; cout << "Balance: $" << Balance() << endl; Restore(f);}BrassPlus::BrassPlus(const string & s, long an, double bal, double ml, double r) :AcctABC(s, an, bal){ maxLoan = ml; owesBank = 0.0; rate = r;}BrassPlus::BrassPlus(const Brass & ba, double ml /* = 500 */, double r /* = 0.10 */) :AcctABC(ba){ maxLoan = ml; owesBank = 0.0; rate = r;}void BrassPlus::ViewAcct() const{ Formatting f = SetFormat(); cout << "BrassPlus Client: " << FullName() << endl; cout << "Account Number: " << AcctNum() << endl; cout << "Balance: $" << Balance() << endl; cout << "Maximum loan: $" << maxLoan << endl; cout << "Owed to bank: $" << owesBank << endl; cout.precision(3); cout << "Loan Rate: " << 100 * rate << "%\n"; Restore(f);}void BrassPlus::Withdraw(double amt){ Formatting f = SetFormat(); double bal = Balance(); if (amt <= bal) AcctABC::Withdraw(amt); else if (amt <= bal + maxLoan - owesBank) { double advance = amt - bal; owesBank += advance * (1.0 + rate); cout << "Bank advance: $" << advance << endl; cout << "Finance charge: $" << advance * rate << endl; Deposit(advance); AcctABC::Withdraw(amt); } else cout << "Credit limit exceeded. Transaction cancelled.\n"; Restore(f);}

13.13 usebrass3.cpp

//usebrass3.cpp -- polymorphic example using an abstract base class//compile with brass.cpp#include 
#include
#include "acctabc.h"const int CLIENTS = 4;int main(){ using namespace std; Brass * p_clients[CLIENTS]; string temp; long tempnum; double tempbal; char kind; for (int i = 0; i < CLIENTS; i++) { cout << "Enter client's name: "; getline(cin, temp); cout << "Enter client's account number: "; cin >> tempnum; cout << "Enter opening balance: $"; cin >> tempbal; cout << "Enter 1 for Brass Account or 2 for BrassPlus Account: "; while (cin >> kind && (kind != '1' && kind != '2')) cout << "Enter either 1 or 2:"; if (kind == '1') p_clients[i] = new Brass(temp, tempnum, tempbal); else { double tmax, trate; cout << "Enter the overdraft limit: $"; cin >> tmax; cout << "Enter the interest rate as a decimal fraction: "; cin >> trate; p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate); } while (cin.get() != '\n') continue; } cout << endl; for (int i = 0; i < CLIENTS; i++) { p_clients[i]->ViewAcct(); cout << endl; } for (int i = 0; i < CLIENTS; i++) { delete p_clients[i]; } cout << "Done.\n"; return 0;}

使用动态内存分配和友元的继承

13.14 dma.h

//dma.h -- inheritance and dynamic memory allocation#ifndef DMA_H_#define DMA_H_#include 
class baseDMA{private: char * label; int rating;public: baseDMA(const char * l = "null", int r = 0); baseDMA(const baseDMA & rs); virtual ~baseDMA(); baseDMA & operator=(const baseDMA & rs); friend std::ostream & operator<<(std::ostream &os, const baseDMA & rs);};class lacksDMA :public baseDMA{private: enum { COL_LEN = 40 }; char color[COL_LEN];public: lacksDMA(const char * c = "blank", const char * l = "null", int r = 0); lacksDMA(const char * c, const baseDMA & rs); friend std::ostream & operator<<(std::ostream & os, const lacksDMA & rs);};class hasDMA :public baseDMA{private: char * style;public: hasDMA(const char*s = "none", const char * l = "null", int r = 0); hasDMA(const char * s, const baseDMA & rs); hasDMA(const hasDMA & hs); ~hasDMA(); hasDMA & operator=(const hasDMA & rs); friend std::ostream & operator<<(std::ostream & os, const hasDMA & rs);};#endif // !DMA_H_

13.15 dma.cpp

//dma.cpp -- dma class methods#include "dma.h"#include 
using namespace std;baseDMA::baseDMA(const char * l /* = "null" */, int r /* = 0 */){ label = new char[strlen(l) + 1]; strcpy(label, l); rating = r;}baseDMA::baseDMA(const baseDMA &rs){ label = new char[strlen(rs.label) + 1]; strcpy(label, rs.label); rating = rs.rating;}baseDMA::~baseDMA(){ delete[] label;}baseDMA & baseDMA::operator=(const baseDMA & rs){ if (this == &rs) return *this; delete[]label; label = new char[strlen(rs.label) + 1]; strcpy(label, rs.label); rating = rs.rating; return *this;}ostream & operator<<(ostream & os, const baseDMA & rs){ os << "Label: " << rs.label << endl; os << "Rating: " << rs.rating << endl; return os;}lacksDMA::lacksDMA(const char * c /* = "blank" */, const char * l /* = "null" */, int r /* = 0 */) :baseDMA(l, r){ strncpy(color, c, 39); color[39] = '\0';}lacksDMA::lacksDMA(const char * c /* = "blank" */, const baseDMA & rs) :baseDMA(rs){ strncpy(color, c, COL_LEN - 1); color[COL_LEN - 1] = '\0';}ostream & operator << (ostream & os, const lacksDMA & ls){ os << (const baseDMA &)ls; os << "Color: " << ls.color << endl; return os;}hasDMA::hasDMA(const char * s, const char * l, int r) : baseDMA(l, r){ style = new char[strlen(s) + 1]; strcpy(style, s);}hasDMA::hasDMA(const char * s, const baseDMA & rs) :baseDMA(rs){ style = new char[strlen(s) + 1]; strcpy(style, s);}hasDMA::hasDMA(const hasDMA & hs) :baseDMA(hs){ style = new char[strlen(hs.style) + 1]; strcpy(style, hs.style);}hasDMA::~hasDMA(){ delete[]style;}hasDMA & hasDMA::operator=(const hasDMA & hs){ if (this == &hs) return *this; baseDMA::operator=(hs); delete[]style; style = new char[strlen(hs.style) + 1]; strcpy(style, hs.style); return *this;}ostream & operator<<(ostream & os, const hasDMA & hs){ os << (const baseDMA &)hs; os << "Style: " << hs.style << endl; return os;}

13.16 usedma.cpp

//usedma.cpp -- inheritance, friends, and DMA//compile with dma.cpp#include 
#include "dma.h"int main(){ using namespace std; baseDMA shirt("Portabelly", 8); lacksDMA balloon("red", "Blimpo", 4); hasDMA map("Mercator", "Buffalo Keys", 5); cout << "Displaying baseDMA object:\n" << shirt << endl; cout << "Displaying lacksDMA object:\n" << balloon << endl; cout << "Displaying hasDMA object:\n" << map << endl; lacksDMA balloon2(balloon); cout << "Result of lacksDMA copy:\n" << balloon2 << endl; hasDMA map2; map2 = map; cout << "Result of hasDMA assignment:\n" << map2 << endl; return 0;}

 

 

转载地址:https://blog.csdn.net/yukinoai/article/details/82916767 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C++Primer Plus笔记——第十三章 类继承课后编程练习答案
下一篇:C++Primer Plus笔记——第十二章 类和动态内存分配课后编程练习答案

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月02日 15时35分12秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章