《C++PrimerPlus》第13章 类继承
2023-12-30 15:38:16
13.1 一个简单的基类
基类和派生类示例(球会会员管理)
头文件tabtenn1.h
#ifndef __TABTENN1_H__
#define __TABTENN1_H__
#include <iostream>
#include <string>
using namespace std;
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
源代码main.cpp
#include <iostream>
#include "tabtenn1.h"
using namespace std;
int main(void)
{
RatedPlayer rplay1(1140, "Mallory", "Duck", false);
rplay1.Name(); // 派生类使用基类的成员函数
if (rplay1.HasTable())
cout << ": has a table." << endl;
else
cout << ": hasn't a table." << endl;
rplay1.Name();
cout << ": Rating: " << rplay1.Rating() << endl;
TableTennisPlayer player1("Tara", "Boomdea", false);
RatedPlayer rplayer2(1212, player1); // 调用第二个构造函数
cout << "Name: ";
rplayer2.Name();
cout << ": Rating : " << rplayer2.Rating() << endl;
return 0;
}
源代码tabtenn1.cpp
#include "tabtenn1.h"
TableTennisPlayer::TableTennisPlayer(const string &fn, const string &ln, bool ht)
{
firstname = fn;
lastname = ln;
hasTable = ht;
}
void TableTennisPlayer::Name() const
{
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.2 继承:is-a关系
13.3 多态公有继承
多态公有继承示例(银行的两类账户)
头文件brass.h
#ifndef __BRASS_H__
#define __BRASS_H__
#include <iostream>
#include <string>
using namespace std;
class Brass {
private:
string fullName; // 客户姓名
long acctNum; // 账号
double balance; // 当前结余
public:
Brass(const string &s = "Null", 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 = "Null", long an = -1, double bal = 0.0,
double ml = 500.0, double rate = 0.11125); // 构造函数
BrassPlus(const Brass &ba, double ml = 500.0, double rate = 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.0; } // 将透支总额复位为0
};
#endif // !__BRASS_H__
源代码main.cpp
#include "brass.h"
const int CLIENTS = 3;
int main()
{
Brass Rick("Rick", 123456, 4000.0);
BrassPlus Jack("Jack", 654321, 3000.0);
Rick.ViewAcct();
cout << endl;
Jack.ViewAcct();
cout << endl;
cout << "Depositing $1000 into the Jack Account." << endl;
Jack.Deposit(1000);
Jack.ViewAcct();
cout << endl;
cout << "Withdraw $4200 from the Rick Account." << endl;
Rick.Withdraw(4200);
Rick.ViewAcct();
cout << endl;
cout << "Withdraw $4200 from the Jack Account." << endl;
Jack.Withdraw(4200);
Jack.ViewAcct();
cout << endl;
/*******************使用引用或指针************************/
// 使用基类指针:可以指向基类对象,也可以指向派生类对象
Brass *p_clients[CLIENTS]; //基类的指针数组,每个元素都是一个基类的指针
string temp;
long tempnum;
double tempbal;
int kind;
for (int i = 0; i < CLIENTS; i++) {
cout << "Enter the 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 << "Please enter either 1 or 2: ";
if (kind == 1)
p_clients[i] = new Brass(temp, tempnum, tempbal); // 对类使用new,将会调用相应的构造函数
else {
double tmax, trate;
cout << "Enter the overdraft limit: $";
cin >> tmax;
cout << "Enter the rate: ";
cin >> trate;
p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);
}
while (cin.get() != '\n'); // 消耗掉回车
}
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]; // 有new就有delete!
}
return 0;
}
源代码brass.cpp
#include "brass.h"
Brass::Brass(const string &s, long an, double bal) {
fullName = s;
acctNum = an;
balance = bal;
}
void Brass::Deposit(double amt) {
if (amt < 0)
cout << "Negative value is not allowed!" << endl;
else
balance += amt;
}
void Brass::Withdraw(double amt) {
if (amt < 0)
cout << "Negative value is not allowed!" << endl;
else if (amt <= balance)
balance -= amt;
else
cout << "Withdraw amount exceeded your balance!" << endl;
}
double Brass::Balance() const {
return balance;
}
void Brass::ViewAcct() const {
cout << "Client: " << fullName << endl;
cout << "Account number: " << acctNum << endl;
cout << "Balance: $" << balance << endl;
}
BrassPlus::BrassPlus(const string &s, long an, double bal, double ml,
double r) : Brass(s, an, bal) {
maxLoan = ml;
rate = r;
owesBank = 0.0;
}
BrassPlus::BrassPlus(const Brass &ba, double ml, double r) : Brass(ba) {
maxLoan = ml;
rate = r;
owesBank = 0.0;
}
void BrassPlus::ViewAcct() const { // 定义的时候不需要加virtual
Brass::ViewAcct(); // 派生类调用基类方法
cout << "Maxium load: $" << maxLoan << endl;
cout << "Loan Rate: " << rate << endl;
cout << "Owed to bank: $" << owesBank << endl;
}
void BrassPlus::Withdraw(double amt) {
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!" << endl;
}
13.4 静态联编和动态联编
13.5 访问控制:protected
13.6 抽象基类
抽象类示例(银行的两类账户)
头文件acctabc.h
#ifndef __ACCTABC_H__
#define __ACCTABC_H__
#include <iostream>
#include <string>
using namespace std;
class AcctABC {
private:
string fullName;
long acctNum;
double balance;
protected:
const string &FullName() const { return fullName; } // 返回客户姓名
long AcctNum() const { return acctNum; } // 返回客户账号
public:
AcctABC(const string &s = "Null", long an = -1,
double bal = 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 = "Null", long an = -1,
double bal = 0.0) : AcctABC(s, an, bal) {} // 创建账户(构造函数)
virtual void Withdraw(double amt); // 取款(虚)
virtual void ViewAcct() const; // 显示账户信息(虚)
virtual ~Brass(){}
};
class BrassPlus : public AcctABC{ // 派生类
private:
double maxLoan; // 透支上限
double rate; // 透支利率
double owesBank; // 当前的透支总额
public:
BrassPlus(const string &s = "Null", long an = -1, double bal = 0.0,
double ml = 500.0, double rate = 0.11125); // 构造函数
BrassPlus(const Brass &ba, double ml = 500.0, double rate = 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.0; } // 将透支总额复位为0
};
#endif // !__BRASS_H__
源代码main.cpp
#include "acctabc.h"
const int CLIENTS = 3;
int main()
{
AcctABC *p_clients[CLIENTS]; //基类的指针数组,每个元素都是一个基类的指针
string temp;
long tempnum;
double tempbal;
int kind;
for (int i = 0; i < CLIENTS; i++) {
cout << "Enter the 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 << "Please enter either 1 or 2: ";
if (kind == 1)
p_clients[i] = new Brass(temp, tempnum, tempbal); // 对类使用new,将会调用相应的构造函数
else {
double tmax, trate;
cout << "Enter the overdraft limit: $";
cin >> tmax;
cout << "Enter the rate: ";
cin >> trate;
p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);
}
while (cin.get() != '\n'); // 消耗掉回车
}
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]; // 有new就有delete!
}
return 0;
}
源代码acctabc.cpp
#include "acctABC.h"
AcctABC::AcctABC(const string &s, long an, double bal) {
fullName = s;
acctNum = an;
balance = bal;
}
void AcctABC::Deposit(double amt) {
if (amt < 0)
cout << "Negative value is not allowed!" << endl;
else
balance += amt;
}
void AcctABC::Withdraw(double amt) {
balance -= amt;
}
void Brass::Withdraw(double amt) {
if (amt < 0)
cout << "Negative value is not allowed!" << endl;
else if (amt <= Balance())
AcctABC::Withdraw(amt);
else
cout << "Withdraw amount exceeded your balance!" << endl;
}
void Brass::ViewAcct() const {
cout << "Client: " << FullName() << endl;
cout << "Account number: " << AcctNum() << endl;
cout << "Balance: $" << Balance() << endl;
}
BrassPlus::BrassPlus(const string &s, long an, double bal, double ml,
double r) : AcctABC(s, an, bal) {
maxLoan = ml;
rate = r;
owesBank = 0.0;
}
BrassPlus::BrassPlus(const Brass &ba, double ml, double r) : AcctABC(ba) {
maxLoan = ml;
rate = r;
owesBank = 0.0;
}
void BrassPlus::ViewAcct() const { // 定义的时候不需要加virtual
cout << "Client: " << FullName() << endl;
cout << "Account number: " << AcctNum() << endl;
cout << "Balance: $" << Balance() << endl;
cout << "Maxium load: $" << maxLoan << endl;
cout << "Loan Rate: " << rate << endl;
cout << "Owed to bank: $" << owesBank << endl;
}
void BrassPlus::Withdraw(double amt) {
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!" << endl;
}
13.7 继承和动态内存分配
继承和动态内存分配示例(派生类使用或不使用new)
头文件dma.h
#ifndef __DMA_H___
#define __DMA_H___
#include <iostream>
using namespace std;
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 &s); // 重载=运算符
friend ostream &operator<<(ostream &os, const baseDMA &rs); // 重载<<运算符
};
class lacksDMA : public baseDMA {
private:
enum { COL_LEN = 40 };
char color[COL_LEN];
public:
lacksDMA(const char *l = "null", int r = 0, const char *c = "blank"); // 构造函数
lacksDMA(const baseDMA &rs, const char *c = "blank");
friend ostream &operator<<(ostream &os, const lacksDMA &rs);
};
class hasDMA : public baseDMA {
private:
char *style;
public:
hasDMA(const char *l = "null", int r = 0, const char *s = "none");
hasDMA(const baseDMA &rs, const char *s);
hasDMA(const hasDMA &hs); // 复制构造函数
~hasDMA(); // 析构函数
hasDMA &operator=(const hasDMA &hs); // 重载=运算符
friend ostream &operator<<(ostream &os, const hasDMA &rs); // 重载<<运算符
};
#endif
源代码main.cpp
#include "dma.h"
int main()
{
baseDMA shirt("Protabelly", 8);
cout << "Displaying baseDMA object: " << endl;
cout << shirt;
cout << "-----------------------------------" << endl;
lacksDMA ballon("Blimpo", 4, "red");
cout << "Displaying lacksDMA object: " << endl;
cout << ballon;
cout << "-----------------------------------" << endl;
lacksDMA ballon2(ballon); // 调用默认复制构造函数
cout << ballon2;
cout << "-----------------------------------" << endl;
hasDMA map("Keys", 5, "Mercator");
cout << "Displaying hasDMA object: " << endl;
cout << map << endl;
cout << "-----------------------------------" << endl;
hasDMA map2 = map; // 使用复制构造函数
cout << map2 << endl;
cout << "-----------------------------------" << endl;
hasDMA map3;
map3 = map; // 使用重载赋值运算符
cout << map3 << endl;
return 0;
}
源代码dma.cpp
#include "dma.h"
#include <cstring>
baseDMA::baseDMA(const char *l, int r) {
label = new char[strlen(l) + 1];
strcpy_s(label, strlen(l) + 1, l);
rating = r;
}
baseDMA::baseDMA(const baseDMA &rs) {
label = new char[strlen(rs.label) + 1];
strcpy_s(label, strlen(rs.label) + 1, 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_s(label, strlen(rs.label) + 1, 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 *l, int r, const char *c) : baseDMA(l, r) {
strncpy_s(color, COL_LEN, c, strlen(c)); // 注意strncpy和strncpy_s的区别
}
lacksDMA::lacksDMA(const baseDMA &rs, const char *c) : baseDMA(rs) {
strncpy_s(color, COL_LEN, c, strlen(c));
}
ostream &operator<<(ostream &os, const lacksDMA &ls) {
os << (const baseDMA &)ls; // 强制类型转换,使用基类的运算符输出基类的信息
os << "Color: " << ls.color << endl;
return os;
}
hasDMA::hasDMA(const char *l, int r, const char *s) : baseDMA(l, r) {
style = new char[strlen(s) + 1];
strcpy_s(style, strlen(s) + 1, s);
}
hasDMA::hasDMA(const baseDMA &rs, const char *s) : baseDMA(rs) {
style = new char[strlen(s) + 1];
strcpy_s(style, strlen(s) + 1, s);
}
hasDMA::hasDMA(const hasDMA &hs) : baseDMA(hs) {
cout << "Copy construct function." << endl; // 标记一下复制构造函数被使用
style = new char[strlen(hs.style) + 1];
strcpy_s(style, strlen(hs.style) + 1, hs.style);
}
hasDMA::~hasDMA() {
delete[] style;
}
hasDMA &hasDMA::operator=(const hasDMA &hs) {
cout << "operator function." << endl; // 标记重载赋值运算符被使用
if (this == &hs) return *this;
// 基类的重载运算符的函数表示法,传递给this指针
// 这里不能写出this,否则会无限递归
baseDMA::operator=(hs);
delete[] style;
style = new char[strlen(hs.style) + 1];
strcpy_s(style, strlen(hs.style) + 1, hs.style);
return *this;
}
ostream &operator<<(ostream &os, const hasDMA &hs) {
os << (const baseDMA &)hs; // 强制类型转换,使用基类的运算符输出基类的信息
os << "Style: " << hs.style << endl;
return os;
}
文章来源:https://blog.csdn.net/Mako5455/article/details/135197275
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!