类继承(3)

抽象基类,纯虚函数,protected关键字,ABC思想

//class.h

#pragma once

#ifndef _CLASS_H_
#define _CLASS_H_

#include<string>
using namespace std;

//多态通过虚函数virtual实现,虚函数在不同的类中可以有着不同的定义,但是声明必须相同
//此时AcctABC为基类(含有Brass和BrassPlus的相同特性),Brass和BrassPlus均为派生类

class AcctABC
{
private:
	string fullName;
	long acctNum;
	double balance;
protected: // 派生类可以直接访问protected中的所有数据和函数
	struct Formatting
	{
		ios_base::fmtflags flag;
		streamsize pr;
	};
	const string& FullName()const
	{
		return fullName;
	}
	long AcctNum()const
	{
		return acctNum;
	}
	Formatting SetFormat()const;
	void Restore(Formatting& f)const;
public:
	AcctABC(const string& s = "Nullbody", long an = -1, double bal = 0.0);
	void Deposit(double amt);
	//纯虚函数
	virtual void Withdraw(double amt) = 0;
	virtual void ViewAcct()const = 0;
	double Balance()const
	{
		return balance;
	};
	virtual ~AcctABC() {};  //基类中的析构函数应设置为虚函数
};

class Brass :public AcctABC
{
public:
	Brass(const string& s = "Nullbody", long an = -1, double bal = 0.0):AcctABC(s,an,bal){ };  //先通过成员初始化创建基类对象,若无新数据,则无需再初始化
	virtual void Withdraw(double amt);
	virtual void ViewAcct()const;
};

class BrassPlus :public AcctABC
{
private:
	double maxLoan;
	double rate;
	double owesBank;
public:
	BrassPlus(const string& s = "Nullbody", long an = -1, double bal = 0.0, double m1 = 500, double r = 0.1);
	BrassPlus(const Brass& ba, double ml = 500, double r = 0.1);
	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

//fuc.cpp

#include<iostream>
#include"class.h"

AcctABC::AcctABC(const string& s, long an, double bal)
{
	fullName = s;
	acctNum = an;
	balance = bal;
}

void AcctABC::Deposit(double amt)
{
	if (amt < 0)
	{
		cout << "Negative deposit not allowed; "
			<< "deposit is cancelled" << endl;
	}
	else
	{
		balance += amt;
	}
}

void AcctABC::Withdraw(double amt)
{
	balance -= amt;
}

AcctABC::Formatting AcctABC::SetFormat()const  //AcctABC::Formatting  声明返回类型是AcctABC类中的Formatting结构体
{
	Formatting f;
	f.flag = cout.setf(ios_base::fixed, ios_base::floatfield);
	f.pr = cout.precision(2);
	return f;
}

void AcctABC::Restore(Formatting& f)const
{
	cout.setf(f.flag, ios_base::floatfield);
	cout.precision(f.pr);
}

void Brass::Withdraw(double amt)
{
	if (amt < 0)
	{
		cout << "Withdrawal amount must be positive;"
			<< "Withdrawal cancelled" << endl;
	}
	else if (amt <= Balance())
	{
		AcctABC::Withdraw(amt);
	}
	else
	{
		cout << "Withdrawal amount of &" << amt
			<< "exceeds your balance." << endl;
		cout << "Withdrawal cancelled" << endl;
	}
}

void Brass::ViewAcct()const
{
	Formatting f = SetFormat();
	cout << "Brass Clinet: " << FullName() << endl; // protected区域函数
	cout << "Account Number: " << AcctNum() << endl; // protected区域函数
	cout << "Balance : $" << Balance() << endl;
	Restore(f);
}

BrassPlus::BrassPlus(const string& s, long an, double bal, double ml, double r) :AcctABC(s, an, bal)  //通过成员初始化先创建基类对象
{
	maxLoan = ml;
	owesBank = 0.0;
	rate = r;
}

//调用基类的默认复制构造函数创建基类对象,复制构造函数的参数是基类对象的引用,所以传递其派生类对象作为参数也是合理的
BrassPlus::BrassPlus(const Brass & ba, double ml, double r) : AcctABC(ba)  
{
	maxLoan = ml;
	owesBank = 0.0;
	rate = r;
}

void BrassPlus::ViewAcct()const
{
	Formatting f = SetFormat();

	cout << "Brass Clinet: " << FullName() << endl; // protected区域函数
	cout << "Account Number: " << AcctNum() << endl; // protected区域函数
	cout << "Balance : $" << Balance() << endl;
	cout << "Maximum loan: $" << maxLoan << endl;
	cout << "Owed to bank: $" << owesBank << endl;
	cout.precision(3);
	cout << "Loan rate: " << 100 * rate << "%\n";
	Restore(f);
}

void BrassPlus::Withdraw(double amt)
{

	double bal = Balance();   //balance是基类中的数据成员,继承类要想访问基类的数据成员必须通过基类的成员函数
	//若存款大于想要取款值
	if (amt <= bal)
	{
		AcctABC::Withdraw(amt);
	}
	//若取款值大于存款+目前可以借款最大值(maxLoan - owesBank 即理论借款最大值减去目前欠银行款)
	else if (amt <= bal + maxLoan - owesBank)
	{
		double advance = amt - bal;
		owesBank += advance * (1 + rate);
		cout << "Bank advance: $" << advance << endl;
		cout << "Finance charge: $" << advance * rate << endl;
		//利用Deposit存入预支款后再使用Brass中的Withdraw取款
		Deposit(advance);
		AcctABC::Withdraw(amt);
	}
	else
	{
		cout << "Your action is negative due to the reason that your balance can not afford the payment" << endl;
	}
}

//main.cpp


//在派生类方法中,标准技术是使用作用域解析运算符('::')来调用基类方法

#include<iostream>
#include"class.h"

const int CLIENTS = 4;

int main()
{
	AcctABC* p_clients[CLIENTS]; //指向抽象基类的指针 -> 具体派生类
	string temp;
	long tempnum;
	double tempbal;
	char kind;

	for (int i = 0; i < CLIENTS; i++)
	{
		cout << "Enter clients name: ";
		getline(cin, temp);    //为string元素输入 getline(cin,stringname)
		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 interest rate"
				<< "as a decimal fraction: ";
			cin >> trate;
			// Brass * p_clients = new BrassPlus()
			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(); //程序将根据指针所指向的对象来判断使用哪个类的ViewAcct()函数  -- 动态联编
		cout << endl;
	}
	for (int i = 0; i < CLIENTS; i++)
	{
		delete p_clients[i];
	}
	cout << "Done" << endl;


	system("pause");
	return 0;
}

知识点:

1.纯虚函数:

  1):纯虚函数即为虚函数声明的结尾处为=0。

eg:

//纯虚函数
	virtual void Withdraw(double amt) = 0;
	virtual void ViewAcct()const = 0;

  2):包含纯虚函数的类只能作为基类 -- 即抽象基类,抽象基类不能创建对象。

  3):纯虚函数可以定义也可以不进行定义。

2.protected关键字: 继承类可以直接访问基类包括在protected区域内的数据和函数 -- 一般用于让派生类访问公共无法访问的内部函数。

 eg:

class AcctABC
{
private:
	string fullName;
	long acctNum;
	double balance;
protected: // 派生类可以直接访问protected中的所有数据和函数
	struct Formatting
	{
		ios_base::fmtflags flag;
		streamsize pr;
	};
	const string& FullName()const
	{
		return fullName;
	}
	long AcctNum()const
	{
		return acctNum;
	}
	Formatting SetFormat()const;
	void Restore(Formatting& f)const;
};

3.ABC思想运用于编程:将少数但对事物起决定性作用的的关键因数放入抽象基类,将种类繁多但对事物影响极小的次要因素放入派生具体类。

  (即从派生类中抽象出相同的特性,再将这些特性放到一个ABC抽象基类中,再从基类派生出派生具体类)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值