C++ Primer Plus书之--C++ 怎么定义一个抽象类

抽象基类(Abstruct base class)

包含纯虚函数的类只用作基类, 要成为抽象基类, 必须至少包含一个纯虚函数.

纯虚函数: 函数原型中的=0使虚函数称为纯虚函数. 例如下面例子中的Area()方法

class BaseEllipse
{
private:
	double x;
	double y;
	
public:
	BaseEllipse(double x0 = 0, double y0 = 0) : x(x0), y(y0) {}
	virtual ~BaseEllipse() {}
	void Move(int nx, int ny)
	{
		x = nx;
		y = ny;
	}
	// 纯虚函数
	virtual double Area() const = 0;
}

这里的方法Area()没有定义, 但C++甚至允许纯虚函数有定义. 例如: 也许所有的基类方法都与Move()一样, 可以在基类中进行定义, 但仍需将这个类声明为抽象的. 在这种情况下, 可以将原型声明为虚的:

void Move(int nx, ny) = 0;

这将使基类成为抽象的, 但仍可以在实现文件中提供方法的定义:

void BaseEllipse::Move(int nx, ny)
{
    x = nx; 
    y = ny;
}

总之, 在原型中使用=0指出类是一个抽象基类, 在类中可以不定义该函数.

抽象类不能用来创建对象

 

 

抽象类的示例:

第一个文件

// acctabc.h
#ifndef ACCTABC_H_
#define ACCTABC_H_
#include <iostream>
#include <string>

// 抽象基类
class AcctABC
{
private:
	std::string fullName;
	long acctNum;
	double balance;
// protected修饰的子类可见, 外部不可见
protected:
	struct Formatting
	{
		std::ios_base::fmtflags flag;
		std::streamsize pr;
	};
	const std::string & FullName() const 
	{
		return fullName;
	}
	long AcctNum() const 
	{
		return acctNum;
	}
	Formatting SetFormat() const;
	void Restore(Formatting & f) const;
	
public:
	AcctABC(const std::string & s = "Default", long an = -1, double bal = 0.0);
	void Deposit(double amt);
	// 纯虚函数, 这个声明也让AcctABC成为了抽象基类
	virtual void Withdraw(double amt) = 0;
	double Balance() const {return balance;}
	// 纯虚函数
	virtual void ViewAcct() const = 0;
	virtual ~AcctABC(){}
};

// 基类Brass
// 由于里面没有纯虚函数, 所以不是抽象基类
class Brass: public AcctABC
{
public:
	// 成员列表方法调用父类的构造函数
	Brass(const std::string & s = "Default", long an = -1, double bal = 0.0): AcctABC(s, an, bal){}
	virtual void Withdraw(double amt);
	virtual void ViewAcct() const;
	// 基类建议都定义一个虚析构函数, 在释放资源的时候能够按正确顺序释放资源
	virtual ~Brass(){}
};

// 派生类
class BrassPlus : public Brass
{
private:
	double maxLoan;
	double rate;
	double owesBank;
	
public:
	// 构造函数原型里不写对父类的构造函数调用的成员列表方法
	BrassPlus(const std::string & s = "Default", long an = -1, double bal = 0.0, double ml = 500, double r = 0.10);
	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 RestOwes() {owesBank = 0;}
};

#endif

 

第二个文件:

// acctabc.cpp
#include <iostream>
#include "acctabc.h"

using std::cout;
using std::ios_base;
using std::endl;
using std::string;

AcctABC::AcctABC(const std::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
{
	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);
}


// Brass methods
void Brass::Withdraw(double amt)
{
	if(amt < 0)
		cout << "Withdrawl amount must be positive; withdrawal canceled" << endl;
	else if(amt <= Balance())
		AcctABC::Withdraw(amt);
	else
		cout << "Withdrawl amount of $" << amt << " exceeds your balance." << endl << "Withdrawal canceled" << endl;
}

void Brass::ViewAcct() const
{
	Formatting f = SetFormat();
	cout << "Brass Client: " << FullName() << endl;
	cout << "Account Number: " << AcctNum() << endl;
	cout << "Balance: $" << Balance() << endl;
	Restore(f);
}


// 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;
}

void BrassPlus::ViewAcct() const
{
	Formatting f = SetFormat();
	
	cout << "BrassPlus Client: " << FullName() << endl;
	cout << "Account Number : " << AcctNum() << endl;
	cout << "Balance: $" << Balance() << endl;
	cout << "Maximum loan: $" << maxLoan << endl;
	cout << "Owed to bank: $" << owesBank << endl;
	cout.precision(3);
	cout << "Loan Rate: " << 100 * rate << "%" << endl;
	Restore(f);
}

void BrassPlus::Withdraw(double amt)
{
	Formatting f = SetFormat();
	
	double bal = Balance();
	if(amt <= bal)
		AcctABC::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);
		AcctABC::Withdraw(amt);
	} else {
		cout << "Credit limit exceeded. Transaction cancelled." << endl;
	}
	Restore(f);
}

调用文件:

// usebrass3.cpp
// compile with acctabc.cpp
#include <iostream>
#include <string>
#include "acctabc.h"

const int CLIMNTS = 4;

int main()
{
	using std::cin;
	using std::cout;
	using std::endl;
	
	AcctABC * p_clients[CLIMNTS];
	std::string temp;
	long tempnum;
	double tempbal;
	char kind;
	
	for(int i = 0; i < CLIMNTS; i++)
	{
		cout << "Enter client's name: ";
		getline(cin, temp);
		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;
			p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);
		}
		while(cin.get() != '\n')
			continue;
	}
	cout << endl;
	for(int i = 0; i < CLIMNTS; i++)
	{
		p_clients[i]->ViewAcct();
		cout << endl;
	}
	
	for(int i = 0; i < CLIMNTS; i++)
	{
		delete p_clients[i];
	}
	cout << "Done" << endl;
	return 0;
}

程序运行结果为:

 重要的地方都写有注释


版权声明:本文为c1392851600原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。