《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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。