虚函数的主要应用场景
虚函数用在多态公有继承中,假设存在Brass类和BrassPlus类,且BrassPlus公有继承于Brass类,BrassPlus将针对自己的类属性,对Brass类部分公有函数进行更改,此时便需要申明virtual。
如下例代码所示:
class Brass
{
private:
string fullName;
long acctNum;
double balance;
public:
// 默认构造函数
Brass(string fn = "None", long an = 0, double bala = 0) :fullName(fn), acctNum(an), balance(bala) { ; }
// 存钱
void deposit(double money);
// 取钱,此函数基类和派生类用法不一样
virtual void withdraw(double money);
double getBalance();
// 查看账户虚函数
// 子类和父类使用方法不一样
virtual void viewAcct();
// 虚析构函数
virtual ~Brass() { ; }
};
// public Brass 指定继承类
class BrassPlus : public Brass
{
private:
double maxLoan; // 最大透支
double rate; // 银行利率
double oweBank; //欠银行的钱
public:
BrassPlus(double, double, double, string, long,double);
BrassPlus(double, double, double, const Brass&);
virtual void withdraw(double money);
virtual void viewAcct();
// 虚析构函数
virtual ~BrassPlus() { ; }
void setMaxLoan(double ml) { maxLoan = ml; }
void setRate(double rt) { rate = rt; }
void setOB(double oB){ oweBank = oB; }
};
其中withdraw,viewAcct函数便为虚函数,虚函数的有无直接决定,引用类型和指针类型所选择的方法,如果使用了virtual程序将根据指针和引用指向的类型来选择方式。
现对上述代码的viewAcct()函数来举例子,假设viewAcct()不是虚函数那么
Brass chen("chentao",1123,1120);BrassPlus tan("0,0,0,chen);
Brass& r1 = chen ; Brass& r2 = tan ; r1.viewAcct(); r2.viewAcct() ; 都是调用Brass::viewAcct()
假设viewAcct()是虚函数,那么上述代码将分别调用Brass::viewAcct()和BrassPlus::viewAcct()
虚析构函数
假设Employee是基类singer是派生类,看如下代码Eployee* pe = new singer; .....delete pe;如果析构函数不是虚函数,则我们使用delete pe的时候,将调用~Eployee()函数,这将释放singer中的Eployee所指向的内存部分,但不会释放新的类成员所指向的内存部分。但如果析构函数是虚的则代码先调用~singer()函数再调用~Eployee()函数。因此基类中的析构函数一定要申明为虚析构函数。
虚成员函数和动态联编
如上述代码所示,Brass chen("chentao",1123,1120);BrassPlus tan("0,0,0,chen);Brass& r1 = chen ; Brass& r2 = tan ; r1.viewAcct(); r2.viewAcct() ;假设viewAcct()不是虚函数,那么他们便为静态联编。而虚函数的过程便为动态联编,即根据实指对象类型来确定调用的函数是Brass::viewAcct()还是BrassPlus::viewAcct()。