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

第十三章类和继承:多态共有继承02

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:多态共有继承


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


前言

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

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


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

二、使用步骤

1.类的实现

代码如下(示例):

//brass.cpp -- bank account class methods
//13.8
#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 cancelled.\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.\n";
	}
	else if (amt<=balance)
	{
		balance -= amt;
	}
	else
	{
		cout << "Withdrawal amount of $" << amt
			<< " exceeds your balance.\n"
			<< "Withdrawal canceled.\n";
	}
	restore(initialState, prec);
}

double Brass::Balance()const
{
	return balance;
}

void Brass::ViewAcct()const
{
	//set ###.##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);//restore original format
}

//BrassPlus methods
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 wiewacct()works
void BrassPlus::ViewAcct()const
{
	//set tup ###.## 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);
}

1.类的实现具体细节分析

介绍程序清单13.8的具体细节(如一些方法的格式化处理)之前,先来看一下与继承直接相关的方面。记住,派生类并不能直接访问基类的私有数据,而必须使用基类的公有方法才能访问这些数据。访问的方式取决于方法。构造函数使用一种技术,而其他成员函数使用另一种技术。

派生类构造函数在初始化基类私有数据时,采用的是成员初始化列表语法。RatedPlayer类构造函数和BrassPlus 构造函数都使用这种技术:

//BrassPlus methods
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)//Uses implicit copy constructor
{
	maxLoan = ml;
	owesBank = 0.0;
	rate = r;
}

这几个构造函数都使用成员初始化列表语法,将基类信息传递给基类构造函数,然后使用构造函数体初始化 BrassPlus 类新增的数据项。

非构造函数不能使用成员初始化列表语法,但派生类方法可以调用公有的基类方法。例如,BrassPlus版本的 ViewAcct()核心内容如下(忽略了格式方面):

//redefine how wiewacct()works
void BrassPlus::ViewAcct()const
{
......
	Brass::ViewAcct();
	cout << "Maximum loan:$" << maxLoan << endl;
	cout << "Owed to bank: $" << owesBank << endl;
	cout << "Loan Rate:" << 100 * rate << "%\n";
.....
}

换句话说,BrassPlus::ViewAcct()显示新增的 BrassPlus 数据成员,并调用基类方法 Brass::ViewAcct()来显示基类数据成员。在派生类方法中,标准技术是使用作用域解析运算符来调用基类方法。代码必须使用作用域解析运算符。假如这样编写代码:


//redefine how wiewacct()works
void BrassPlus::ViewAcct()const
{

	Brass::ViewAcct();//oops,recursive call

}

如果代码没有使用作用域解析运算符,编译器将认为ViewAcct()是 BrassPlus::ViewAcct(),这将创建
个不会终止的递归函数–这可不好。接下来看 BrassPlus:Withdraw()方法。如果客户提取的金额超过了结余,该方法将安排贷款。它可以使用 Brass::Withdraw()来访问 balance成员,但如果取款金额超过了结余,Brass:Withdraw()将发出一个错误消息。这种实现使用 Deposit()方法进行放贷,然后在得到了足够的结余后调用 Brass::Withdraw,从而避免了错误消息:

//redefine how withdraw()works
void BrassPlus::Withdraw(double amt)
{
....
	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";
	}
	....
}

该方法使用基类的 Balance()函数来确定结余。因为派生类没有重新定义该方法,代码不必对 Balance()使用作用域解析运算符。
方法 ViewAcct()和 Withdraw()使用格式化方法 set()和 precision( )将浮点值的输出模式设置为定点,即包含两位小数。设置模式后,输出的模式将保持不变,因此该方法将格式模式重置为调用前的状态。这与程序清单8.8和程序清单10.5类似。为避免代码重复,该程序将设置格式的代码放在辅助函数中:

//formatting stuff
typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setFormat();
void restore(format f, precis p);

而函数restore()重置格式和精度

void restore(format f, precis p)
{
	cout.setf(f, std::ios_base::floatfield);
	cout.precision(p);
}

有关设置输出格式的更详细信息,请参阅第十七章

2.使用Brass和BrassPlus类

在下一篇文中中展开

总结

提示:这里对文章进行总结:

暂无

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值