理解继承、虚函数与多态
示例代码(摘自《深入浅出MFC》)
第一节:
使用VS2005生成一个console程序,添加MyTestClass.h将如下代码添加到该头文件中
#include "string.h"
/*
CEmployee是基类
CWage、CManager为CEmployee的派生类
CSales为CWage的派生类
*/
// Base Class 职员
class CEmployee
{
private:
char m_Name[30];
public:
CEmployee();
CEmployee(const char *nm)
{
strcpy_s(m_Name,sizeof(m_Name),nm);
}
void getname()
{
printf("%s/n",m_Name);
}
};
class CWage:public CEmployee
{
private:
float m_wage;
float m_hours;
public:
CWage(const char *nm) : CEmployee(nm)
{
m_wage = 250.0;
m_hours = 40.0;
}
float computePay()
{
return (m_wage * m_hours);
}
};
class CSales:public CWage
{
private:
float m_comm;
float m_sale;
public:
CSales(const char *nm):CWage(nm)
{
m_comm = m_sale = 0.0;
}
void SetCommission(float comm)
{
m_comm = comm;
}
float computePay()
{
return ( CWage::computePay() + m_comm * m_sale);
}
};
class CManager:public CEmployee
{
private:
float m_salary;
public:
CManager(const char *nm):CEmployee(nm)
{
m_salary = 1500.0;
}
void setSalary(float salary)
{
m_salary = salary;
}
float computePay()
{
return m_salary;
}
};
添加一个.cpp文件,并在cpp文件中添加如下代码:
#include "stdafx.h"
#include "MyTestClass.h"
int _tmain(int argc, _TCHAR* argv[])
{
CManager aManager("管理");
CSales aSales("销售");
CWage aWager("其它");
CEmployee *pEmployee[3];
pEmployee[0] = &aManager;
pEmployee[1] = &aSales;
pEmployee[2] = &aWager;
for (int i=0; i<3; i++)
pEmployee[i]->getname();
return 0;
}
输出结果会怎样呢?因为 CWage、CManager为CEmployee的派生类,CSales为CWage的派生类,所有的对象均从CEmployee派生出来,所以都会继承CEmplyee的成员,即所有的对象都有和getname函数。但是同一函数怎样处理不同的数据?为什么只调用了getname却可以处理不同的名称?实际上是this指针的功能,编译器在编译过后生成的代码中会添加一个隐匿的参数:this指针。在类的成员变量前面会加入this->来标志究竞是哪个对象正在处理。实际上当在处理CManager aManager("管理");时基类CEmployee中的m_Name成员变量前面加入了一个this指针,该指针就指向了对象aManager。所以程序输出结果为:
管理
销售
其它
现在我如果把CSales稍为改造一下,变成如下的样子,其它代码不作改动
class CSales:public CWage
{
private:
float m_comm;
float m_sale;
char szName[30];
public:
CSales(const char *nm):CWage(nm)
{
m_comm = m_sale = 0.0;
strcpy(szName,nm);
}
void SetCommission(float comm)
{
m_comm = comm;
}
float computePay()
{
return ( CWage::computePay() + m_comm * m_sale);
}
void getname()
{
printf("销售类中的:%s/n",szName);
}
};
我只是在CSales中加入了一个与基类相同的函数getname,那程序的输出结果会怎样呢?
程序将输出基类中的字符串呢?还是子类中的字符串呢?运行一下,输出结果如下
管理
销售
其它
为什么在第二行中不输出 “销售类中的:销售”这个字符串呢?哦,原因是:如果基类与派生类都定义了“相同名称这成员函数”,那么通过对象指针调用成员函数时,到底调用哪一个函数,必须视该指针的原始类型而定,而不是视指针实际所指的对象的类型而定。上面的例子中,指向对象的指针定义为CEmployee *pEmployee[3];那指针的原始类型为CEmployee,所以当然会执行CEmployee中的getname了。所以会有如上的输出结果。为了验证这个结论,我们再将.cpp文件修改一下,在for循环前面加入这么两行代码
CSales *pSales = &aSales;
pSales->getname();
或干脆点,变成这样的
CSales *pSales;
pEmployee[1] = pSales = &aSales;
pSales->getname();
同样是把aSales对象的地址赋给两个指针,执行结果会一样吧?呵呵,运行一下:
销售类中的:销售
管理
销售
其它
结果如上,看样子是与该指针的原始类型决定了成员函数的调用。