从一个类派生出另一个类,原始类成为基类,继承类称为派生类。
虚函数:无virtual 程序根据引用类型或指针类型选择方法,有virtual程序将根据引用或指针指向的对象的类型做选择。
支票代码如下:
brass.h
- #ifndef BRASS_H_
- #define BRASS_H_
-
- #include <string>
-
- using std::string;
-
- class Brass
- {
- private:
- string fullName;
- long acctNum;
- double balance;
- public:
- Brass(const string &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() {};
- };
-
- class BrassPlus : public Brass
- {
- private:
- double maxLoan;
- double rate;
- double owesBank;
- public:
- BrassPlus(const string &s= "NullBody",long an = -1,double bal = 0.0,double ml =500,double r = 0.11125 );
- BrassPlus(const Brass &ba,double ml = 500,double r = 0.11125);
- 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
brass.cpp
- #include <iostream>
- #include "brass.h"
-
- using namespace std;
-
- typedef ios_base::fmtflags format;
- typedef streamsize precis;
- format setFormat();
- void restore(format f,precis p);
-
- Brass::Brass(const string &s,long an,double bal)
- {
- fullName = s;
- acctNum = an;
- balance = bal;
- }
-
- void Brass::Deposit(double amt)
- {
- if(amt < 0)
- cout << "Negative deposit, deposit is cancelled.\n";
- else
- balance += amt;
- }
-
- void Brass::Withdraw(double amt)
- {
- format initState = setFormat();
- precis prec = cout.precision(2);
-
- if(amt < 0)
- cout << "Withdraw canceled\n";
- else if(amt <= balance)
- balance -= amt;
- else
- cout << "Withdraw amount of $" << amt << " exceeds your balance.\n" << "Withdraw canceled\n";
- restore(initState,prec);
- }
-
- double Brass::Balance() const
- {
- return balance;
- }
-
- void Brass::ViewAcct() const
- {
- format initialstate = setFormat();
- precis prec = cout.precision(2);
- cout << "Client: " << fullName << endl;
- cout << "Account Number:" << acctNum << endl;
- cout << "Balance: $" << balance << endl;
- restore(initialstate,prec);
- }
-
- 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
- {
- format initialstate = setFormat();
- precis prec = cout.precision(2);
-
- Brass::ViewAcct();
- cout << "Maxinum loan:$" << maxLoan <<endl;
- cout << "Owed to bank:$" << owesBank << endl;
- cout.precision(3);
- cout << "Loan Rate: " << 100*rate << "%\n";
- restore(initialstate,prec);
- }
-
- void BrassPlus::Withdraw(double amt)
- {
- format initialstate = setFormat();
- precis prec = 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 << "Transaction cancelled.\n";
- restore(initialstate,prec);
- }
-
- format setFormat()
- {
- return cout.setf(ios_base::fixed,ios_base::floatfield);
- }
-
- void restore(format f,precis p)
- {
- cout.setf(f,ios_base::floatfield);
- cout.precision(p);
- }
usebrass1.cpp
- #include <iostream>
- #include "brass.h"
-
- using namespace std;
-
- int main()
- {
- Brass pig("pigg",381299,4000.00);
- BrassPlus Hoggy("Hogg",382288,3000.00);
- pig.ViewAcct();
- cout << endl;
- Hoggy.ViewAcct();
- cout << endl;
- cout << "Hogg + 1000$\n";
- Hoggy.Deposit(1000);
- cout << "Hoggy bal:$" << Hoggy.Balance() << endl;
- cout <<"withdeaw $4200 from pig\n";
- pig.Withdraw(4200);
- cout <<"pig bal:$" << pig.Balance() << endl;
- cout <<"withdraw $4200 from Hogg\n";
- Hoggy.Withdraw(4200);
- Hoggy.ViewAcct();
- return 0;
- }
虚方法行为 多态性
usebrass2.cpp
- #include <iostream>
- #include <string>
- #include "brass.h"
-
- const int CLIENTS = 4;
- using namespace std;
-
- int main()
- {
- Brass* p_client[CLIENTS];
- string temp;
- long tempnum;
- double tempbal;
- char kind;
-
- for(int i=0;i<CLIENTS;i++)
- {
- cout << "enter client's name:";
- getline(cin,temp);
- cout << "enter client's accout number:";
- cin >> tempnum;
- cout << "enter opening balance:$";
- cin >> tempbal;
- cout << "enter 1 for brass accout or 2 for brassplus accout:";
- while(cin >> kind && (kind != '1' && kind != '2'))
- cout << "enter 1 or 2:";
- if(kind == '1')
- p_client[i] = new Brass(temp,tempnum,tempbal);
- else
- {
- double tmax,trate;
- cout << "enter overdraft limit:&";
- cin >> tmax;
- cout << "enter the rate:";
- cin >> trate;
- p_client[i] = new BrassPlus(temp,tempnum,tempbal,tmax,trate);
-
- }
- while(cin.get() != '\n')
- continue;
- }
- cout << endl;
- for(int i =0;i<CLIENTS;i++)
- {
- p_client[i]->ViewAcct();
- cout << endl;
- delete p_client[i];
- }
- cout << "Done!\n";
- return 0;
- }
运行结果:
- enter client's name:harry
- enter client's accout number:112233
- enter opening balance:$1500
- enter 1 for brass accout or 2 for brassplus accout:1
- enter client's name:dinah
- enter client's accout number:121213
- enter opening balance:$1800
- enter 1 for brass accout or 2 for brassplus accout:2
- enter overdraft limit:&350
- enter the rate:0.12
- enter client's name:brenda
- enter client's accout number:212118
- enter opening balance:$5200
- enter 1 for brass accout or 2 for brassplus accout:2
- enter overdraft limit:&800
- enter the rate:0.1
- enter client's name:tim
- enter client's accout number:233255
- enter opening balance:$688
- enter 1 for brass accout or 2 for brassplus accout:1
-
- Client: harry
- Account Number:112233
- Balance: $1500.00
-
- Client: dinah
- Account Number:121213
- Balance: $1800.00
- Maxinum loan:$350.00
- Owed to bank:$0.00
- Loan Rate: 12.000%
-
- Client: brenda
- Account Number:212118
- Balance: $5200.00
- Maxinum loan:$800.00
- Owed to bank:$0.00
- Loan Rate: 10.000%
-
- Client: tim
- Account Number:233255
- Balance: $688.00
-
- Done!
注意虚函数viewAcct()的调用。
基类的虚析构函数是很有必要的。
程序中有重载函数时,编译器根据参数完成函数对应,会再编译过程中完成联编,称为静态联编。
增加虚函数后,编译器需要在程序运行时对应函数,称为动态联编。
将派生类引用或指针 转换为 基类引用或者指针 称为向上强制转换,这使公有继承不需要进行显示类型转换。is-a规则
- void fr(Brass &rb); //uses rb.ViewAcct()
- void fp(Brass *rp); //uses rp->ViewAcct()
- void fv(Brass &b); //uses b.ViewAcct()
- int main()
- {
- Brass b("bill",123432,10000);
- BrassPlus bp("betty",232323,12345);
- fr(b); //uses Brass::ViewAcct()
- fr(bp); //uses BrassPlus::ViewAcct()
- fp(b); //uses Brass::ViewAcct()
- fp(bp); //uses BrassPlus::ViewAcct()
- fv(b); //uses Brass::ViewAcct()
- fv(bp); //uses Brass::ViewAcct()
- }
虚函数在内存和执行速度方面有一定成本:
虚函数还需注意事项
派生类可以直接访问基类保护成员。
最好对数据成员采用私有访问控制,不要使用保护控制。
abstract base class ABC
在函数原型中使用=0指出类时一个抽象基类,在类中可以不定义该函数
代码示例
acctabc.h
- #ifndef ACCTABC_H_
- #define ACCTABC_H_
- #include <iostream>
- #include <string>
-
- class AcctABC
- {
- private:
- std::string fullName;
- long acctNum;
- double balance;
- 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 = "Nullbody",long an = -1,double bal = 0.0);
- void Deposit(double amt);
- virtual void Withdraw(double amt) = 0;
- 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.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.0,double ml = 500,double r=1.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 ResetRate(double r) {rate = r;}
- void ResetOwes() {owesBank = 0;}
- };
-
- #endif
acctabc.cpp
- #include <iostream>
- #include "acctabc.h"
-
- using namespace std;
-
- 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, deposit is cancelled.\n";
- 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);
- }
-
- void Brass::Withdraw(double amt)
- {
- if(amt < 0)
- cout << "Withdraw canceled\n";
- else if(amt <= Balance())
- AcctABC::Withdraw(amt);
- else
- cout << "Withdraw amount of $" << amt << " exceeds your balance.\n" << "Withdraw canceled\n";
- }
-
- void Brass::ViewAcct() const
- {
- Formatting f = SetFormat();
- cout << "Client: " << FullName() << endl;
- cout << "Account Number:" << AcctNum() << endl;
- 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 << "Client: " << FullName() << endl;
- cout << "Account Number:" << AcctNum() << endl;
- cout << "Balance: $" << Balance() << endl;
- cout << "Maxinum 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)
- {
- 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 << "Transaction cancelled.\n";
- Restore(f);
- }
usebrass3.cpp
- #include <iostream>
- #include <string>
- #include "acctabc.h"
-
- const int CLIENTS = 4;
- using namespace std;
-
- int main()
- {
- AcctABC* p_client[CLIENTS];
- string temp;
- long tempnum;
- double tempbal;
- char kind;
-
- for(int i=0;i<CLIENTS;i++)
- {
- cout << "enter client's name:";
- getline(cin,temp);
- cout << "enter client's accout number:";
- cin >> tempnum;
- cout << "enter opening balance:$";
- cin >> tempbal;
- cout << "enter 1 for brass accout or 2 for brassplus accout:";
- while(cin >> kind && (kind != '1' && kind != '2'))
- cout << "enter 1 or 2:";
- if(kind == '1')
- p_client[i] = new Brass(temp,tempnum,tempbal);
- else
- {
- double tmax,trate;
- cout << "enter overdraft limit:&";
- cin >> tmax;
- cout << "enter the rate:";
- cin >> trate;
- p_client[i] = new BrassPlus(temp,tempnum,tempbal,tmax,trate);
-
- }
- while(cin.get() != '\n')
- continue;
- }
- cout << endl;
- for(int i =0;i<CLIENTS;i++)
- {
- p_client[i]->ViewAcct();
- cout << endl;
- delete p_client[i];
- }
- cout << "Done!\n";
- return 0;
- }
未完待续