秒懂面向对象编程之继承(C++实例研究)
实例要求:(Account继承层次)创建银行帐户的继承层次结构,表示银行的所有客户账户。所有的客户都可以把钱存入他们的账户,然后取出来,但账户也可以分成更具体的类型。例如,一方面存储账户SavingsAccount从存款中获得利息;另一方面,支票账户CheckingAccount对每笔交易(即存款或取款)都要收费。
创建一个类层次,以Account作为基类, SavingsAccount和CheckingAccount作为派生类。基类Account应该包括一个double 类型的数据成员balance,表示账户的余额。该类应提供一个构造函数,接受一个初始余额值并用它初始化数据成员balance。而且构造函数确认初始余额的有效性,保证它大于等于0。如果小于0,则需将其置为0,并显示出错信息,表明该初始化余额是一个无效的值。该类应当提供三个成员函数:成员函教credit可以向当前余额加钱;成员函数debit负责从账户中取钱,并且保证账户不会透支。如果提取金额大于账户余额,函数将保持balance不变,并打印信息"Debit amount exceeded account balance";成员函数getBalance则返回当前balance的值。
派生类SavingsAccount不仅继承了基类Account的功能,而且还应提供一个附 加的double类型数据成员interestrate表示这个账户的利率了(百分比)。SavingsAccount的构造函数应接受初始余额值和初始利率值,还应提供一个public成员函数calculatelnterest,返回代表账户的利息的一个double 值,这个值是balance和interestrate的乘积。注意:类SavingsAccount应继承成员函数credit和debit,不需要重新定义。
派生类CheckingAccount不仅继承了基类Account的功能,还应提供一个附加的double类型数据成员fcargedpetransaction表示每笔交易的费用。CheckingAccount的构造函数应接受初始余额值和交易费用值。类CheckingAccount需要重新定义成员函数credit和debit ,当每笔交易完成时,从batance中减去fechargedpertransaction。 重新定义成员函数时应用(即调用)到基类Account的这两个函数来执行账户余额的更新。CheckingAccount的debit函数只有当钱被成功提取时(即提取金额不超过账户余额时)才应收取交易费。
提示:定义Account的debit函数使它返回一个bool类型值,表示钱是否被成功提取。然
后利用该值决定是否需要扣除交易费。
当这个层次中的类定义完毕后,编写一个程序, 要求创建每个类的对象并测试它们的成员函数。将利息加到SavingsAccount对象的方法是:先调用它的成员calculatelnterest,然后将返回的利息数传递给该对象的credit值。
`
继承的特性:
(一)、私有数据是private型的继承:
1、基类在派生类的类名后面写出
class A :public B//A是派生,B是基类,被公有继承
2、派生类的构造函数里面的参数值一定要给够,包括基类里面的参数。因为在派生类的构造函数会调用基类的构造函数。
注意:在这种情况下在派生类的函数实现中直接使用基类的私有数据成员会报错。
(二)、私有数据是protected型的继承:
解决了直接使用私有数据成员报错的问题,利用protected下的私有数据成员后直接使用私有数据成员不会报错。
注意:这种情况下也有不便之处,就是如果在基类中的私有数据成员写错了,要修改时要进行基类和派生类的成员共同修改。我们想要达到的效果是直接修改基类中的信息,派生类就跟着被修改,这就是下面一种方式。
(三)、私有数据是private型的继承:
这种方式的做法:
(1)、在基类中要用到私有数据成员时,用它的接口函数代替。
(2)、在派生类中使用基类的接口函数时,如果该接口函数在基类和派生类中有同样的函数名时,在调用它的时候一定要在函数名前加上基类的类名+二元作用域运算符。
部分解析伪代码:
//Account.cpp
<构造函数(初始参数)>
{
if( 参数 >= 0)
< 赋值给私有数据成员 >
else
<输出错误信息提示用户>
<私有数据成员 = 0.0 >
}
存钱函数credit实现:
<函数原型(参数)>
{
balance = balance + 参数;
}
取钱函数debit实现:
<函数原型 (参数)>
{
if(参数 > balance)
cout << <输出错误信息提示>;
return false;
else
<进行取钱重置balance>
return true;
}
派生类中的构造函数:
<函数原型(参数1,参数2)>//参数1用于初始化基类中的私有数据成员
:基类的构造函数(参数1)//成员初始化器初始化
{
<初始化派生类中的私有数据成员>
}
完整代码展示(附详细注释):
// Account.h
// 定义 Account类
#ifndef ACCOUNT_H
#define ACCOUNT_H
class Account
{
public:
Account( double ); // 构造函数初始化balance
void credit( double ); // 在balance的基础上加钱函数
bool debit( double ); //从balance账户上取钱函数
void setBalance( double ); //设置balance函数
double getBalance(); //返回balance函数
private:
double balance; //私有数据成员balance
};
#endif
//Account.cpp
//Account类的接口函数的具体实现
#include <iostream>
using std::cout;
using std::endl;
#include "Account.h" //包含头文件Account类
//构造函数初始化 balance
Account::Account( double initialBalance )//传入一个最初余额的参数
{
if ( initialBalance >= 0.0 )//如果最初的余额大于0元
balance = initialBalance;//将传进的数据存入私有数据成员balance
else //如果最初的余额小于0元
{
cout << "Error: Initial balance cannot be negative." << endl;//输出错误提示信息
balance = 0.0;//将余额置为0元
}
}
// 加钱的函数credit的实现
void Account::credit( double amount )//传入一个金额
{
balance = balance + amount; //加到原有的金额上重置balance
}
// 取钱函数debit的实现
// 判断是否符合取钱的条件
bool Account::debit( double amount )//传入一个需要取走的金额
{
if ( amount > balance ) //如果要取得金额大于账户里的余额
{
cout << "Debit amount exceeded account balance." << endl;//输出提示不能取
return false;
}
else //如果要取得金额小于账户里的余额
{
balance = balance - amount;//进行取钱操作并重置余额
return true;
}
}
// 设置账户余额the account balance函数实现
void Account::setBalance( double newBalance )//传入一个新的balance
{
balance = newBalance;//重置balance
}
//获取余额函数
double Account::getBalance()
{
return balance;//返回账户余额
}
//SavingsAccount.h
//定义第一个派生类SavingsAccount class.
#ifndef SAVINGS_H
#define SAVINGS_H
//需要包含的头文件
#include "Account.h"
//由基类Account派生出新类SavingsAccount
class SavingsAccount : public Account//公有继承
{
public:
//派生类中的构造函数,需要提供基类的构造函数的参数
SavingsAccount(double = 0 ,double = 0);
double calculateInterest();//定义一个新的成员函数:返回账户所得的利息
private:
double interetRate;//新的数据成员利率interetRate
};
#endif
//SavingsAccount.cpp
//派生类SavingsAccount接口函数的实现
#include "SavingsAccount.h" //包含所在类的头文件
//派生类的构造函数的实现
SavingsAccount::SavingsAccount(double a ,double b)
:Account(a)//调用基类中的构造函数初始化基类中的数据成员
{
interetRate = b;//初始化派生类中新增的数据成员
}
double SavingsAccount::calculateInterest()//计算利息函数的实现
{
return interetRate * getBalance();//若用到基类的私有数据成员,必须用基类中的接口函数代替
/*return interetRate * Account::getBalance();*/
//如果基类和派生类中的接口函数相同,需加上基类的类名和二元作用域运算符
}
// CheckingAccount.h
// 定义的第二个派生类CheckingAccount
#ifndef CHECKING_H
#define CHECKING_H
//包含基类的头文件
#include "Account.h"
//由基类Account派生出新类CheckingAccount
class CheckingAccount : public Account
{
public:
//派生类中的构造函数,需提供基类中数据成员的参数
CheckingAccount(double = 0,double = 0);
//取钱完成时,从balance减去费用transactionFee函数的实现
void credit( double );
//判断是否交易成功,然后决定是否要扣费函数的实现
bool debit(double);
private:
double transactionFee;//新增的私有数据成员交易费用transactionFee
void chargeFee();//工具函数进行扣费操作的实现
};
#endif
//CheckingAccount.cpp
//派生类CheckingAccount接口函数的实现
#include <iostream>
using std::cout;
using std::endl;
#include "CheckingAccount.h" //包含所在类的头文件
//第二个派生类的构造函数实现
CheckingAccount::CheckingAccount(double a,double b)
:Account(a)//调用基类的构造函数初始化基类的数据成员
{
transactionFee = (b > 0) ? b : 0;//对交易费的有效性的检查
}
// credit 函数的实现
void CheckingAccount::credit(double amount)//传入一个金额
{
Account::credit(amount);//调用基类中的加钱函数进行加钱操作
}
//取钱函数并扣除手续费的实现
bool CheckingAccount::debit(double amount)//传入要取的金额
{
if ( Account::debit( amount ) ) // 判断是否符合取钱的标准,调用基类中的debit函数判断
{
chargeFee();//如果符合则取钱
return true;
}
else
return false;
}
//取钱函数的实现
void CheckingAccount::chargeFee()
{
Account::setBalance(Account::getBalance() - transactionFee );//从基类中返回的余额扣除手续费在作为新的余额传入基类的设置函数
cout << "$" << transactionFee << "transaction fee charged." << endl;
}
//bankAccounts.cpp
// 测试代码
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setprecision;
using std::fixed;
#include "Account.h" // 基类
#include "SavingsAccount.h" // 第一个派生类
#include "CheckingAccount.h" // 第二个派生类
int main()
{
Account account1( 50.0 ); // 初始化基类中余额为50
SavingsAccount account2( 25.0, .03 ); // 初始化基类中余额为25,利率为0.03
CheckingAccount account3( 80.0, 1.0 ); // 初始化基类中余额为20,取钱的手续费为1元
cout << fixed << setprecision( 2 );
cout << "account1 balance: $" << account1.getBalance() << endl;//输出对象account1的余额,50
cout << "account2 balance: $" << account2.getBalance() << endl;//输出对象account2的余额,25
cout << "account3 balance: $" << account3.getBalance() << endl;//输出对象account3的余额,80
cout << "\nAttempting to debit $25.00 from account1." << endl;
account1.debit( 25.0 ); //给对象account1取钱25
cout << "\nAttempting to debit $30.00 from account2." << endl;
account2.debit( 30.0 ); // 给对象account2取钱30
cout << "\nAttempting to debit $40.00 from account3." << endl;
account3.debit( 40.0 ); //给对象account3取钱40
cout << "\naccount1 balance: $" << account1.getBalance() << endl;//输出取钱后对象account1的余额25
cout << "account2 balance: $" << account2.getBalance() << endl;//输出取钱后对象account2的余额25
cout << "account3 balance: $" << account3.getBalance() << endl;//输出取钱后对象account3的余额39
cout << "\nCrediting $40.00 to account1." << endl;
account1.credit( 40.0 ); // 给对象account1存钱40
cout << "\nCrediting $65.00 to account2." << endl;
account2.credit( 65.0 ); // 给对象account2存钱65
cout << "\nCrediting $20.00 to account3." << endl;
account3.credit( 20.0 ); // 给对象account3存钱20
cout << "\naccount1 balance: $" << account1.getBalance() << endl;//输出存钱后对象account1的余额65
cout << "account2 balance: $" << account2.getBalance() << endl;//输出存钱后对象account2的余额90
cout << "account3 balance: $" << account3.getBalance() << endl;//输出存钱后对象account3的余额58
//计算account2余额所获得的利息
double interestEarned = account2.calculateInterest();
cout << "\nAdding $" << interestEarned << " interest to account2."
<< endl;
//将利息再存入account2
account2.Account::credit( interestEarned );
cout << "\nNew account2 balance: $" << account2.getBalance() << endl;//输出最后account 的余额
return 0;
}