C++ day24 继承(四)抽象基类,纯虚函数,protected

关键字protected(带来方便同时带来危险,最好不用)

关于访问控制,即访问类的私有数据成员,之前一直是只用private和public来控制的。现在介绍一个新工具,关键字protected,但他并不是一个多好的东西,有利有弊,是一把双刃剑,使用双刃剑一定要十分小心,很容易杀敌一万自损八千,其实最好不要用这个关键字。下面仔细解释我说的这些。

private数据成员,外部不可以访问,必须通过类的公有接口访问。所以上篇文章写银行账户取款方法和存款方法的时候,访问账户余额必须要通过公有方法Balance()才可以访问到私有数据成员balance,看似麻烦(要多写一个返回私有数据成员的值的方法),实则安全。因为银行账户类的设计,希望账户余额绝对安全,只能让存款取款方法访问和改写余额的值,这样,余额不可能被其他方法修改,是很安全的。

现在有了关键字protected,我们为了方便,不想写Balance()方法,于是干脆把余额设为保护成员,而非私有成员

protected:
	double balance;

保护成员的双重身份:
保护成员对于外部世界和私有成员一样,不可以被直接访问,必须通过类的公有接口;
但是对于派生类,以及派生链条上的所有类,保护成员却和公有成员一样,任何派生类都可以直接访问他们。

对于我们的程序,在plus会员派生类中确实不需要写Balance()方法访问balance成员了,可以直接在派生类的方法中访问,方便了,但也危险了,因为派生类的任何方法都可以修改余额,派生类的派生类,派生链条上的所有类,的公有方法都可以随意修改余额。。。你敢把钱存到这家银行吗?

所以protected是一个给成员函数偷懒的好工具,但是如果不是脑子里很清楚被派生类随意访问并无大碍,那就不要用保护成员,乖乖设置为私有成员(C++的开创者Stroustrup都是这么建议的),然后写一个返回其值的公有方法,并不很费神,但百分百安全,毫无后顾之忧,何乐而不为呢?

balance是私有成员,用Balance()访问,下面是派生类取钱方法的代码,要用double bal = Balance();,如果balance是保护成员,则后面都直接用balan
ce了

void BrassPlus::Withdraw(double amt)//虚方法
{
   
	format initialState = setFormat();
	precis prec = std::cout.precision(2);

	double bal = Balance();
	if (amt < 0)
		std::cout << "Withdraw amount must be positive!\n"
				  << "Withdraw cancelled!\n";
	else if (amt <= bal)//不可写amt <= balance,因为不能直接访问基类数据成员
		Brass::Withdraw(amt);//不可写balance -= amt;
	else if(amt - bal + owesBank <= maxLoan)
	{
   
		double advance = amt - bal;
		owesBank += advance * (1.0 + rate);//rate是BrassPlus类的私有成员
		std::cout << "Bank advance: $" << advance << '\n';
		std::cout << "Finance charge: $" << advance * rate << '\n';
		//分两步实现扣除账户全部余额(由于基类不允许取款金额超出余额,所以只能先存再取)
		Deposit(advance);//放贷
		Brass::Withdraw(amt);
	}
	else
		std::cout << "Credit limit exceeded. Transaction cancelled.\n";

	restore(initialState, prec);
}

抽象基类和纯虚函数(is-a关系用公有继承实现有时候也不太合适)

前面说了有三种继承——公有继承,私有继承,保护继承。

但是目前还是一直在讨论公有继承。

我们说到基类和派生类的五种常见关系:is-a, has-a, is-like-a, uses-a, is-implemented-by-a,其中只有is-a用公有继承来实现是比较好的,其他四个关系都不适合公有继承。

但是现在我们又要说,is-a关系和公有继承之间也不是百分百合拍,完美和谐。有时候,is-a关系不能简单使用公有继承,否则麻烦不断后患无穷,总之不是好的设计。

用圆和椭圆的笨拙派生为例,挑拨is-a和公有继承的搭档关系

数学上,圆是一种特殊的椭圆,是椭圆的一个特例,特殊在于长半轴和短半轴长度相等。于是满足is-a关系,于是我们使用公有继承,从Ellipse类派生出Circle类。

Ellipse类声明,私有数据成员包括位置坐标,长短半轴长度,角度。方法有移动,旋转,缩放。

由于Circle类也要用这三种方法,所以都设置为了虚函数。

由于Ellipse类要成为基类,所以设置了虚析构函
数。

//ellipse.h
#ifndef ELLIPSE_H_
#define ELLIPSE_H_

class Ellipse{
   
private:
    double x;//位置横坐标
    double y;//位置纵坐标
    double a;//长半轴
    double b;//短半轴
    double angle;//x轴和长轴的夹角
public:
    Ellipse(double nx = 0.0, double ny = 0.0, double na = 1.0, double nb = 1.0, double ang = 0.0):x(nx), y(ny), a(na), b(nb), angle(ang){
   }
    virtual ~Ellipse(){
   }
    virtual void Move(double mx, double my){
   x = mx;y = my;}
    virtual void Rotate(double ang){
   angle += ang;}
    virtual void Scale(double sx, double sy){
   a *= sx; b *= sy;}
};
#endif // ELLIPSE_H_

于是Circle类的声
明是

//circle.h
#ifndef CIRCLE_H_
#define CITCLE_H_

class Circle : public Ellipse
{
   
public:
    Circle(double nx, double ny, double a, double b):x(nx), y(ny), a(r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值