C++Primer Plusノート——第十三章類継承総括及びプログラムリスト

19717 ワード

目次
本章のまとめ
プログラムリスト
単純なベースクラス
クラスを派生
マルチステート公有継承
抽象ベースクラス
動的メモリ割り当てと友元の継承の使用
本章のまとめ
       継承既存のクラス(ベースクラス)を使用して新しいクラス(派生クラス)を定義することで、必要に応じてプログラミングコードを変更できます.公有継承はis-a関係を確立し、派生クラスオブジェクトも何らかのベースクラスオブジェクトであるべきであることを意味する.is-aモデルの一部として、派生クラスはベースクラスのデータメンバーとメソッドの大部分を継承しますが、ベースクラスの構造関数、構造関数、および付与演算子は継承されません.派生クラスは、ベースクラスの共有メンバーと保護メンバーに直接アクセスでき、ベースクラスの共有メソッドと保護メソッドを使用してベースクラスのプライベートメンバーにアクセスできます.派化クラスにデータメンバーとメソッドを追加したり、派生クラスをベースクラスとして使用したりして、さらなる開発を行うことができます.各派生クラスには、独自のコンストラクション関数が必要です.プログラムが派生クラスオブジェクトを作成すると、まずベースクラスのコンストラクション関数を呼び出し、次に派生クラスのコンストラクション関数を呼び出す.プログラムがオブジェクトを削除すると、まず派生クラスの構造関数が呼び出され、次にベースクラスの構造関数が呼び出されます.
       クラスをベースクラスとして使用する場合は、メンバーをプライベートではなく保護として宣言できます.これにより、派生クラスはこれらのメンバーに直接アクセスできます.しかしながら、プライベートメンバーの使用は、通常、プログラミングの問題が発生する可能性を低減することができる.派生クラスがベースクラスのメソッドを再定義できるようにする場合は、キーワードvirtualを使用して虚として宣言できます.これにより、ポインタまたは参照によってアクセスされるオブジェクトは、参照またはポインタのタイプではなく、オブジェクトのタイプに応じて処理することができる.具体的には、ベースクラスの構造関数は通常虚であるべきである.
       実装にかかわらず、インタフェースのみを定義するABCの定義を考慮することができます.たとえば、抽象クラスShapeを定義し、CircleやSquareなどの特定の形状クラスを派生させることができます.ABCは少なくとも1つの純虚メソッドを含み、宣言のセミコロンの前に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.
"; else cout << ": hasn't a table.
"; player2.Name(); if (player2.HasTable()) cout << ": has a table.
"; else cout << ": hasn't a table.
"; 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.
"; else cout << ": hasn't a table.
"; player1.Name(); if (player1.HasTable()) cout << ": has a table.
"; else cout << ": hasn't a table.
"; 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:
"; 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.
"; else if (amt <= balance) balance -= amt; else cout << "Withdrawal amount of $" << amt << " exceeds your balance.
" << "Withdrawal canceled.
"; 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 << "%
"; 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.
"; 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 usebrass 1.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:
"; Hoggy.Deposit(1000.00); cout << "New balance: $" << Hoggy.Balance() << endl; cout << "Withdrawing $4200 from the Pigg Account:
"; Piggy.Withdraw(4200.00); cout << "Pigg account balance: $" << Piggy.Balance() << endl; cout << "Withdrawing $4200 from the Hogg Account:
"; Hoggy.Withdraw(4200.00); Hoggy.ViewAcct(); return 0; }

13.10 usebrass 2.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() != '
') 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.
"; 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:
"; 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.
"; else if (amt <= Balance()) AcctABC::Withdraw(amt); else cout << "Withdrawal amount of $" << amt << " exceeds your balance.
" << "Withdrawal canceled.
"; } 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 << "%
"; 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.
"; 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() != '
') 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.
"; 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<

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<

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:
" << shirt << endl; cout << "Displaying lacksDMA object:
" << balloon << endl; cout << "Displaying hasDMA object:
" << map << endl; lacksDMA balloon2(balloon); cout << "Result of lacksDMA copy:
" << balloon2 << endl; hasDMA map2; map2 = map; cout << "Result of hasDMA assignment:
" << map2 << endl; return 0; }