您的位置:首页 > 其它

继承--is-a关系

2016-07-05 21:10 302 查看
    C++有3种继承方式:公有继承、保护继承、私有继承。公有继承是最常用的方式,它建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行。

    如果希望同一个方法在派生类和基类中的行为是不同的,也就是说,方法的行为应取决于调用该方法的对象。这种较复杂的行为成为多态--具有多种形态,就是指同一个方法的想行为随上下文而异。有两种机制可用于实现多态公有继承:

1.在派生类中重新定义基类的方法。

2.使用虚方法。

    为了说明上述性质,我们来看另一个例子:一个类用于 表示基本支票账户-Brass,另一个类用于表示代表Brass Plus支票账户,它添加了透支保护特性。也就是说,如果用户签出一张超出其存款余额的支票--但是超出的数额不是很大,银行将支付这张支票,对超出的部分收取额外的费用,并追加罚款。

下面是用于Brass支票账户的信息:

1.客户姓名

2.账户

3.当前余额

下面是可执行的操作:

1.创建账户

2.存款

3.取款

4.显示账户信息

而Brass Plus包含Brass的所有信息以及以下信息项:

1.透支上限

2.透支贷款利率

3.当前透支总额

不需要新增操作,担有两种操作的实现不同

1.对于取款操作,必须考虑透支保护

2.显示操作必须显示Brass Plus账户的其他信息
我们将第一个类命名为Brass,第二个类为BrassPlus。很明显,应从Prass公有派生出PrassPlus类。

程序清单 brass.h

//brass.h--bank account classes
#ifndef BRASS_H_
#define BRASS_H_

//Brass Account class
class Brass
{
private:
enum {MAX=35};
char fullName[MAX];
long acctNum;
double balance;
public:
Brass (const char *s = "Nullbody",long an = -1,
double bal = 0.0);
void Deposit(double amt);
virtual void withdraw(double amt);
double Balance()const;
virtual void ViewAcct()const;
virtual ~Brass(){}
};

//Brass plus Account Class
class BrassPlus: public Brass
{
private:
double maxloan;
double rate;
double owesBank;
public:
BrassPlus(const char *s = "Nullbody",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 ReseRate(double r){rate = r;}
void ResetOwes(){owesBank = 0;}
};
#endif
对于上述程序清单,有以下说明:

BrassPlus类在Brass类的基础上添加了3个私有数据成员和3个公有成员函数。

Brass类和BrassPlus类都声明了ViewAcct()和Widthdraw()方法,但BrassPlus对象和Brass对象的这些方法的行为是不同的。

Brass类在声明ViewAcct()和Withdraw()时使用了新关键字virtual。这些方法被称为虚方法(virtual method)。

Brass还声明了一个虚拟析构函数,虽然该函数没进行任何操作。

记住:如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚拟的,这样,程序将根据对象类型而不是引用或指针的类型来选择方法版本;为基类声明一个虚拟析构函数也是一种惯例。

程序清单 brass.cpp

//brass.cpp--bank account class methods
#include <iostream>
#include <cstring>
#include "brass.h"

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

//Brass methods
Brass::Brass(const char *s,long an,double bal)
{
std::strncpy(fullName,s,MAX - 1);
fullName[MAX - 1] - '\0';
acctNum = an;
balance = bal;
}

void Brass::Deposit(double amt)
{
if (amt < 0)
cout << "Neqative deposit not allowed: "
<< "deposit is cancelled.\n";
else
balance += amt;
}

void Brass::withdraw(double amt)
{
if (amt < 0)
cout << "Withdrawal amount must be positive: "
<< "withdrawall canceled.\n";
else if (amt <= balance)
balance -= amt;
else
cout << "Withdrawal amount of $" << amt
<< " exceeds your balance.\n"
<< "Withdrawal canceled.\n";
}

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

void Brass::ViewAcct()const
{
//set up ####.## format
ios_base::fmtflags initialState =
cout.setf(ios_base::fixed,ios_base::floatfield);
cout.setf(ios_base::showpoint);
cout.precision(2);
cout << "Client: " << fullName << endl;
cout << "Account Number: " << acctNum << endl;
cout << "Balance: $" << balance << endl;
cout.setf(initialState);//restore original format
}

//BrassPlus Methods
BrassPlus::BrassPlus(const char *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 viewacct()works
void BrassPlus::ViewAcct()const
{
//set up ###.## format
ios_base::fmtflags initalState =
cout.setf(ios_base::fixed,ios_base::floatfield);
cout.setf(ios_base::showpoint);
cout.precision(2);

Brass::ViewAcct();//display base portion
cout << "Maximum loan: $" << maxloan << endl;
cout << "Owed to bank: $" << owesBank << endl;
cout << "Loan Rate: " << 100 * rate <<
"%\n";
cout.setf(initalState);
}

//redefine how Withdraw()works
void BrassPlus::Withdraw(double amt)
{
//set up ###.## format
ios_base::fmtflags initalState =
cout.setf(ios_base::fixed,ios_base::floatfield);
cout.setf(ios_base::showpoint);
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";
cout.setf(initalState);
}

解析:

1.这里面的构造函数都使用成员初始化列表句法,将基类的信息传递给基类 的构造函数,然后使用构造函数初始化BrassPlus类新增的数据项。

2.非构造函数不能采用成员初始化列表句法,但派生类方法可以调用公有的基类方法。

记住:派生类并不能直接访问基类的私有数据,而必须使用基类的公有方法才能访问这些数据,访问的方式取决于方法。

使用Brass和BrassPlus类

程序清单 usebrass1.cpp
//usebrass1.cpp--testing bank account classes
//compile with brass.cpp
#include <iostream>
#include "brass.h"

int main(int argc, char * argv [ ])
{
using std::cout;
using std::endl;

Brass Piggy("Porcelot Pigg",381299,4000.00);
BrassPlus Hoggy("Horatio Hogg",382288,3000.00);
Piggy.ViewAcct();
cout << endl;
Hoggy.ViewAcct();
cout << endl;
cout << "Depositing $1000 into the Hogg Account: \n";
Hoggy.Deposit(1000.00);
cout << "New balance: $" << Hoggy.Balance() << endl;
cout << "Withdrawing $4200 from the Pigg Accout: \n";
Piggy.withdraw(4200.00);
cout << "Pigg accout balance $" << Piggy.Balance() << endl;
c
4000
out << "Withdrawing $4200 from the Hogg Account: \n";
Hoggy.Withdraw(4200.00);
Hoggy.ViewAcct();

return 0;
}


注意:如果在派生类中重新定义了基类的方法,则将它设置为虚方法,否则,设置为非虚方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  继承 class 结构 struct