C++PrimerPlus:第十三章类和继承:多态共有继承01

系列文章目录


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

多态公有继承13.3
RatedPlayer 继承示例很简单。派生类对象使用基类的方法,而未做任何修改。然而,可能会遇到这样的情况,即希望同一个方法在派生类和基类中的行为是不同的。换句话来说,方法的行为应取决于调用该方法的对象。这种较复杂的行为称为多态–具有多种形态,即同一个方法的行为随上下文而异。有两种重要的机制可用于实现多态公有继承;

  • 在派生类中重新定义基类的方法。
  • 使用虚方法。

现在来看另一个例子。由于 Webtown俱乐部的工作经历,您成了Pontoon银行的首席程序员。银行要求您完成的第一项工作是开发两个类。一个类用于表示基本支票账户–Brass Account,另一个类用于表示代表 Brass Plus 支票账户,它添加了透支保护特性。也就是说,如果用户签出一张超出其存款余额的支票–但是超出的数额并不是很大,银行将支付这张支票,对超出的部分收取额外的费用,并追加罚款。可以根据要保存的数据以及允许执行的操作来确定这两种账户的特征。下面是用于 Brass Account 支票账户的信息:
客户姓名;
账号;
当前结余。
下面是可以执行的操作:
创建账户;
存款;
取款;
显示账户信息。
Pontoon 银行希望 Brass Plus 支票账户包含 Brass Account 的所有信息及如下信息:
透支上限;
透支贷款利率;
当前的透支总额。

不需要新增操作,但有两种操作的实现不同:

  • 对于取款操作,必须考虑透支保护:
  • 显示操作必须显示 Brass Plus 账户的其他信息。

假设将第一个类命名为Brass,第二个类为BrassPlus。应从Brass 公有派生出 BrassPlus吗?要回答这个问题,必须先回答另一个问题:BrassPlus类是否满足is-a条件?当然满足。对于 Brass 对象是正确的事情,对于 BrassPlus对象也是正确的。它们都将保存客户姓名、账号以及结余。使用这两个类都可以存款、取款和显示账户信息。请注意,is-a关系通常是不可逆的。也就是说,水果不是香蕉:同样,Brass 对象不具备BrassPlus对象的所有功能。


提示:以下是本篇文章正文内容,下面案例可供参考

一、开发Brass类和BrassPlus类

Brass Account 类的信息很简单,但是银行没有告诉您有关透支系统的细节。当您向友好的 Pontoon 银行代表询问时,他提供了如下信息:

  • Brass Plus 账户限制了客户的透支款额。默认为500元,但有些客户的限额可能不同;
  • 银行可以修改客户的透支限额;
  • Brass Plus 账户对贷款收取利息。默认为11.125%,但有些客户的利率可能不同;
  • 银行可以修改客户的利率;
  • 账户记录客户所欠银行的金额(透支数额加利息)。用户不能通过常规存款或从其他账户转账的方式偿付,而必须以现金的方式交给特定的银行工作人员。如果有必要,工作人员可以找到该客户。
    欠款偿还后,欠款金额将归零。

最后一种特性是银行出于做生意的考虑而采用的,这种方法有它有利的一面–使编程更简单。
上述列表表明,新的类需要构造函数,而且构造函数应提供账户信息,设置透支上限(默认为500元)和利率(默认为 11.125%)。另外,还应有重新设置透支限额、利率和当前欠款的方法。要添加到 Brass 类中的就是这些,这将在BrassPlus类声明中声明。
有关这两个类的信息声明,类声明应类似于程序清单13.7.

二、使用步骤

1.程序清单13.7 brass.h

代码如下(示例):

//brass.h -- bank  account classes
#ifndef brass_h_
#define brass_h_
#include<string>	
//Brass Account Class
class Brass
{
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();
private:
	std::string fullName;
	long acctNum;
	double balance;
};

#endif // !brass_h_

对于程序清单 13.7,需要说明的有下面几点:

  • BrassPlus类在Brass类的基础上添加了3个私有数据成员和3个公有成员函数;
  • *Brass 类和 BrassPlus 类都声明了 ViewAcct()和 Withdraw()方法,但 BrassPlus 对象和 Brass 对象的这些方法的行为是不同的;
  • Brass 类在声明 VewAcct( )和 Withdraw()时使用了新关键字 virtual。这些方法被称为虚方法( virtualmethod):
  • Brass 类还声明了一个虚析构函数,虽然该析构函数不执行任何操作。

第一点没有什么新鲜的。

RatedPlayer 类在TableTennisPlayer类的基础上添加新数据成员和2个新方法
的方式与此类似。

第二点介绍了声明如何指出方法在派生类的行为的不同。

两个ViewAcct()原型表明将有2个独立的方法定义。基类版本的限定名为Brass::ViewAcct(),派生类版本的限定名为BrassPlus:ViewAcct()。程序将使用对象类型来确定使用哪个版本:

Brass dom("Dminic Banker",11111,333.3);
BrassPlus dot("Dorothy",11111,4444.4);
dom.ViewAcct();//use Brass::viewAcct()
dot.ViewAcct();//use BrassPlus::ViewAcct();

同样,Withdraw()也有2个版本,一个供 Brass对象使用,另一个供 BrassPlus 对象使用。对于在两个类中行为相同的方法(如 Deposit()和 Balance()),则只在基类中声明。

第三点(使用 virtual)比前两点要复杂。

如果方法是通过引用或指针而不是对象调用的,它将确定使用哪一种方法。如果没有使用关键字 virual,程序将根据引用类型或指针类型选择方法;如果使用了 virtual,程序将根据引用或指针指向的对象的类型来选择方法。如果ViewAcct()不是虚的,则程序的行为如下:
//behavior with non-virtual ViewAcct()
//method chosen according to reference type
Brass dom(“Dominic Banker”,1111,1211.4);
BrassPlus dot("dorothy Banker ,11,11.9);
Brass& b1_ref = dom;
BrassPlus & b2_ref = dot;
b1_ref.ViewAcct();
b2_ref.ViewAcct();
这里两个引用的类型都是Brass,但b2ref引用的是一个BrassPlus对象,所以使用的是BrassPlus::ViewAcct()。使用 Brass 指针代替引用时,行为将类似。稍后您将看到,虚函数的这种行为非常方便。因此,经常在基类中将派生类会重新定义的方法声明为虚方法。方法在基类中被声明为虚的后,它在派生类中将自动成为虚方法。然而,在派生类声明中使用关键字 virtual来指出哪些函数是虚函数也不失为一个好办法。

第四点是,基类声明了一个虚析构函数。

这样做是为了确保释放派生对象时,按正确的顺序调用析构函数。本章后面将详细介绍这个问题。


注意:如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚的。这样,程序将根据对象类型而不是引用或指针的类型来选择方法版本。为基类声明一个虚析构函数也是一种惯例。

总结:

暂无

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值