派生类可以直接访问基类中protected的成员,但却不能访问private的成员,其他情况下,两者的作用差不多。最好对类数据成员采用私有访问控制,不要使用保护访问控制;同时用过基类方法使派生类能够访问基类数据。然而,对于成员函数来说,保护访问控制很有效,它让派生类能够访问公共不能使用的内部函数。
下面介绍一下抽象基类:
抽象基类的应用很重要,例如,园是椭圆的一种,可以把圆当成椭圆的派生,但是,这会造成一个问题,椭圆有很多属性,对圆来说是没有用的,这样就会造成信息浪费,但是,椭圆和圆都有一些属性石相同的,因此,我们可以从它两者身上抽象出一个抽象基类ABC,椭圆和圆都可以从它派生出来。
但是,需要注意的是,椭圆和圆的面积计算公式不一样,所以,在抽象基类中可以定义一个纯虚函数。包含虚函数的类只能用于基类。要成为抽象基类,必须包含至少一个纯虚函数。
下面是对上个程序应用抽象基类的改变
acctabc.h
#ifndef ACCTABC_H_
#define ACCTABC_H_
#include<iostream>
#include<string>
class AcctABC
{
public:
std::string fullName;
long acctNum;
double balance;
protected:
struct Formatting<span style="white-space:pre"> </span>//这是标准结构输出形式,将数据按。。。形式输出
{<span style="white-space:pre"> </span>
std::ios_base::fmtflags flag;<span style="white-space:pre"> </span>
std::streamsize pr;
};
const std::string & FullName()const{return fullName;}<span style="white-space:pre"> </span>//不能直接访问fullName?求指导
long AcctNum()const{return acctNum;}
Formatting SetFormat()const;
void Restore(Formatting & f)const;
public:
AcctABC(const std::string & s="Nullbody",long an=-1,double bal=0);
void Deposit(double amt);
virtual void Withdraw(double amt)=0;<span style="white-space:pre"> </span>//这就是纯虚函数
double Balance()const{return balance;};
virtual void ViewAcct()const=0;
virtual ~AcctABC(){}
};
class Brass:public AcctABC
{
public:
Brass(const std::string &s="Nullbody",long an=-1,double bal=0):AcctABC(s,an,bal){}
virtual void Withdraw(double amt);
virtual void ViewAcct()const;
virtual ~Brass(){}
};
class BrassPlus:public AcctABC
{
private:
double maxLoan;
double rate;
double owesBank;
public:
BrassPlus(const std::string &s="Nullbody",long an=-1,double bal=0,double max=500,double ra=0.1,double owes=0):AcctABC(s,an,bal)
{
maxLoan=max;
rate=ra;
owesBank=owes;
}
BrassPlus(const AcctABC &ba,double max=500,double ra=0.1,double owes=0):AcctABC(ba){}
virtual void Withdraw(double amt);
virtual void ViewAcct()const;
void ResetMax(double m){maxLoan=m;}
void ResetRate(double r){rate=r;}
};
#endif
从上面头文件可以看出,构造函数变成了内联函数,这样,他的定义就变成下面:
acctabc.cpp
#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::Withdraw(double amt)
{
balance-=amt;
}
void AcctABC::Deposit(double amt)
{
if(amt<0)
{
cout<<"Negative deposit not allowed;"<<"deposit is cancelled."<<endl;
}
else
{
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(2);
}
//Brass::Brass(const std::string &s,long an,double bal):AcctABC(s,an,bal)
//{}
void Brass::Withdraw(double amt)
{
if(amt<0)
{
cout<<"Withdrawal amount must be positive; Withdrawal canceled."<<endl;
}
else if(amt<Balance())
{
balance-=amt;
}
else
{
cout<<"Withdrawal amount of $"<<amt<<" exceeds your balance."<<endl;
cout<<"Withdrawal canceled."<<endl;
}
}
void Brass::ViewAcct()const
{
Formatting f=SetFormat();
cout<<"Bras Client:"<<FullName()<<endl;
/*cout<<"Account Number:"<<acctNum<<endl;*/
cout<<"Account Number:"<<AcctNum()<<endl;
cout<<"Balance:$"<<Balance()<<endl;
Restore(f);
}
//BrassPlus::BrassPlus(const std::string &s,long an,double bal,double ml,double r):AcctABC(s,an,bal)<span style="white-space:pre"> </span>如果不是将构造函数内联到类定义里去了,那么构造函数//就应该这样定义
//{
// maxLoan=ml;
// owesBank=0;
// rate=r;
//}
void BrassPlus::ViewAcct()const
{
Formatting f=SetFormat();
cout<<"Bras Client:"<<FullName()<<endl;
// cout<<"Account Number:"<<acctNum<<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();
if(amt<0)
{
cout<<"Withdrawal amount must be positive; Withdrawal canceled."<<endl;
}
else if(amt<balance)
{
balance-=amt;
}
else if(amt<(balance+maxLoan-owesBank))
{
owesBank=(amt-balance)*(1+rate);
cout<<"Bank advance:$"<<(amt-balance)<<endl;
cout<<"Finance charge:$"<<(amt-balance)*rate<<endl;
balance=0;
}
else
{
cout<<"Credit limit exceeded.Transaction cancelled."<<endl;
}
Restore(f);
}
usebrass3.cpp
#include"acctabc.h"
const int clients=4;
int main()
{
using namespace std;
AcctABC *p_clients[clients];
std::string temp;
long tempnum;
double tempbal;
char kind;
for(int i=0;i<clients;i++)
{
cout<<"Enter clients' 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 eighter 1 or 2:";
if(kind=='1')
p_clients[i]=new Brass(temp,tempnum,tempbal);
else/* if(kind=='2')*/
{
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<clients;i++)
{
p_clients[i]->ViewAcct();
cout<<endl;
}
for(int i=0;i<clients;i++)
{
delete p_clients[i];
}
cout<<"Done."<<endl;
system("pause");
return 0;
}
由于对象时指针,所以按指针指向的类型调用函数,而不是按指针的类型调用函数