实例导入:
brass.h
//brass.h -- bank account classes
#ifndef BRASS_H_
#define BRASS_H_
#include <string>
//Brass Account Class
class Brass
{
private:
std::string fullName;
long acctNum;
double balance;
public:
Brass(const std::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() {}
};
//Brass Plus Account Class
class BrassPlus :public Brass
{
private:
double maxLoan;
double rate;
double owesBank;
public:
BrassPlus(const std::string& s = "Nullbody", long an = -1, double bal = 0.0, double m1 = 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.cpp
//brass.cpp -- bank account class methods
#include <iostream>
#include "brass.h"
using std::cout;
using std::endl;
using std::string;
//formatting stuff
typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setFormat();
void restore(format f, precis p);
//Brass methods
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 deposit not allowed; " << "deposit is canselled.\n";
else
balance += amt;
}
void Brass::Withdraw(double amt)
{
//set up format
format initialState = setFormat();
precis prec = cout.precision(2);
if (amt < 0)
cout << "Withdrawal amount must be positive; " << "withdrawal canceled." << endl;
else if (amt <= balance)
balance -= amt;
else
cout << "Withdraw amount of $" << amt << " exceds your balance." << endl << "Withdrawal canceled.\n";
restore(initialState, prec);
}
double Brass::Balance() const
{
return balance;
}
void Brass::ViewAcct() const
{
//set up format
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;
}
BrassPlus::BrassPlus(const Brass& ba, double ml, double r) :Brass(ba)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
//redefine how ViewAcct() works
void BrassPlus::ViewAcct() const
{
//set up format
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);
}
//redefine how Withdraw() works
void BrassPlus::Withdraw(double amt)
{
//set up format
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(std::ios_base::fixed, std::ios_base::floatfield);
}
void restore(format f, precis p)
{
cout.setf(f, std::ios_base::floatfield);
cout.precision(p);
}
usebrass.cpp
//usebrass2.cpp -- polymorphic example
//compile with brass.cpp
#include<iostream>
#include<string>
#include"brass.h"
const int CLIENTS = 4;
int main()
{
using std::cin;
using std::cout;
using std::endl;
Brass* p_clients[CLIENTS];
std::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 interst 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;
}
代码解析:
(1)
class BrassPlus :public Brass
{
……
}
从一个类派生另一个类时,原始类称为基类,继承类称为派生类,需使用关键字public
基类的公有成员将成为派生类的公有成员:基类的私有部分也会成为派生类的一部分,但只能通过
基类的公有和保护方法访问。
(2)成员初始化列表:
Brass::Brass(const string& s, long an, double bal) :fullName(s),
acctNum(an), balance(bal){}
初始化列表语法可直接使用string的复制构造函数将fullName初始化为s。如果不使用初始化列表,
会先调用string的默认构造函数再调用赋值运算符将fullName初始化为s,增加一个步骤导致所用时
间变长。
(3)
BrassPlus::BrassPlus(const Brass& ba, double ml, double r) :Brass(ba)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
派生类的构造函数必须使用基类的构造函数,因此可以使用成员初始化列表将BrassPlus中属于
Brass的部分初始化为ba,其余类成员可按一般办法初始化。
(4)
Brass* p_clients[CLIENTS];
……
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 interst rate " << "as a decimal fraction: ";
cin >> trate;
p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);
}
基类指针或引用只能用于调用基类方法,但是基类指针可以在不进行显示类型转换的情况下指向派
生类对象,基类引用也是类似。同时,不可以将基类对象和地址赋给派生类引用和指针。
(5)
virtual void Withdraw(double amt);
……
virtual void Withdraw(double amt);
虚方法:类在声明类方法时在前添加关键字virtual,这种方法成为虚方法。
如果没有使用关键字virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,程序
将根据引用或指针指向的对象的类型来选择方法。
virtual ~Brass() {}
虚析构函数是为了确保释放派生对象时,按正确的顺序调用析构函数,依次释放派生类new分配的
内存和基类new分配的内存。
Brass指针既可以指向Brass对象,也可以指向BrassPlus对象,因此可以使用一个数组来表示多种
类型的对象,这就是多态性。
(6)
typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setFormat();
void restore(format f, precis p);
为避免代码重复,该程序将设置格式的代码放在辅助函数内。
代码在使用过程中,设置模式后,输出的模式不变,可以将格式模式重置为调用前的状态。
(7)
void BrassPlus::ViewAcct() const
{
……
Brass::ViewAcct();
……
}
在派生类中使用类方法需要加上作用域解析运算符,不然可能会创建一个不会终止的递归函数。
(8)
while (cin >> kind && (kind != '1' && kind != '2'))
cout << "Enter either 1 or 2: ";
在输入kind的同时还能检测是否输入正确,输入错误还需要及时修改!
|