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
13.2 tabtenn0.cpp
13.3 usett0.cpp
クラスを派生
13.4 tabtenn1.h
13.5 tabtenn1.cpp
13.6 usett.cpp
マルチステート公有継承
13.7 brass.h
13.8 brass.cpp
13.9 usebrass 1.cpp虚メソッド特性を使用していない
13.10 usebrass 2.cpp虚メソッド特性の使用
抽象ベースクラス
13.11 acctabc.h
13.12 acctabc.cpp
13.13 usebrass3.cpp
動的メモリ割り当てと友元の継承の使用
13.14 dma.h
13.15 dma.cpp
13.16 usedma.cpp
本章のまとめ
プログラムリスト
単純なベースクラス
クラスを派生
マルチステート公有継承
抽象ベースクラス
動的メモリ割り当てと友元の継承の使用
本章のまとめ
継承既存のクラス(ベースクラス)を使用して新しいクラス(派生クラス)を定義することで、必要に応じてプログラミングコードを変更できます.公有継承は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;
}