深入浅出MFC第2版(PDF格式)-第22部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
。 明明都是调用 :: (其实也就是 :: ),却能够
rect1 m_color rect2。m_color this
有条不紊地分别处理 。 和 ?答案在于所谓的 指针。下
一节我就会提到它。
59
…………………………………………………………Page 122……………………………………………………………
3。 既然所有类别都有displ ay 动作,把它提升到老祖宗CShape 去,然后再继承
之,好吗?不好,因为displ ay 函数应该因不同的形状而动作不同。
displ ay f or while
4。 如果 不能提升到基础类别去,我们就不能够以一个 循环或
循环干净漂亮地完成下列动作(此种动作模式在对象导向程序方法中重要无
比):
CShape shapes'5';
。。。 // 5 shapes
令 个 各为矩形、四方形、椭圆形、圆形、三角形
for (int i=0; im_color = color; }
};
我们拨开了第一道疑云。
61
…………………………………………………………Page 124……………………………………………………………
虚拟函数与多态(Polymorphism)
我曾经说过,前一个例子没有办法完成这样的动作:
CShape shapes'5';
。。。 // 5 shapes
令 个 各为矩形、四方形、椭圆形、圆形、三角形
for (int i=0; idisplay();
Ellipse Square Triangle Rect Circle Square Circle Circle
为了支持这种能力,C++ 提供了所谓的虚拟函数(virtual function )。
+ ?!
虚拟 函数 听起来很恐怖的样子。如果你了解汽车的离合器踩下去代表汽车空档,
空档表示失去引擎本身的牵制力,你就会了解「高速行驶间煞车绝不能踩离合器」的道
理并矢志遵行。好,如果你真的了解为什么需要虚拟函数以及什么情况下需要它,你就
能够掌握它的灵魂与内涵,真正了解它的设计原理,并且发现认为它非常人性。并且,
真正知道怎么用它。
62
…………………………………………………………Page 125……………………………………………………………
让我用另一个例子来展开我的说明。这个范例灵感得自Visual C++ 手册之一:
Introdoction to C++。假设你的类别种类如下:
CEmployee
CEmployee
CManager CWage
CManager CWage
CSales
CSales
本图以Visual C++ 之「Class Info 窗口」获得
程序代码实作如下:
#0001 #include
#0002
#0003 //……………………………………………………………………………………………………………………………………………………………………
#0004 class CEmployee // 职员
#0005 {
#0006 private:
#0007 char m_name'30';
#0008
#0009 public:
#0010 CEmployee();
#0011 CEmployee(const char* nm) { strcpy(m_name; nm); }
#0012 };
63
…………………………………………………………Page 126……………………………………………………………
#0013 //……………………………………………………………………………………………………………………………………………………………………
#0014 class CWage : public CEmployee // 时薪职员是一种职员
#0015 {
#0016 private :
#0017 float m_wage;
#0018 float m_hours;
#0019
#0020 public :
#0021 CWage(const char* nm) : CEmployee(nm) { m_wage = 250。0; m_hours = 40。0; }
#0022 void setWage(float wg) { m_wage = wg; }
#0023 void setHours(float hrs) { m_hours = hrs; }
#0024 float putePay();
#0025 };
#0026 //……………………………………………………………………………………………………………………………………………………………………
#0027 class CSales : public CWage // 销售员是一种时薪职员
#0028 {
#0029 private :
#0030 float m_m;
#0031 float m_sale;
#0032
#0033 public :
#0034 CSales(const char* nm) : CWage(nm) { m_m = m_sale = 0。0; }
#0035 void setmission(float m) { m_m = m; }
#0036 void setSales(float sale) { m_sale = sale; }
#0037 float putePay();
#0038 };
#0039 //……………………………………………………………………………………………………………………………………………………………………
#0040 class CManager : public CEmployee // 经理也是一种职员
#0041 {
#0042 private :
#0043 float m_salary;
#0044 public :
#0045 CManager(const char* nm) : CEmployee(nm) { m_salary = 15000。0; }
#0046 void setSalary(float salary) { m_salary = salary; }
#0047 float putePay();
#0048 };
#0049 //……………………………………………………………………………………………………………………………………………………………………
#0050 void main ()
#0051 {
#0052 CManager aManager(〃陈美静〃);
#0053 CSales aSales(〃侯俊杰〃);
#0054 CWage aWager(〃曾铭源〃);
#0055 }
#0056 //……………………………………………………………………………………………………………………………………………………………………
#0057 // 虽然各类別的 putePay 函数都没有定义,但因为程序也没有调用之,所以无妨。
64
…………………………………………………………Page 127……………………………………………………………
如此一来,CWage 继承了CEmpl oyee 所有的成员(包括资料与函数),CSales 又继承
了CWage 所有的成员(包括资料与函数)。在意义上, 相当于CSales 拥有资料如下:
// private data of CEmployee
char m_name'30';
// private data of CWage
float m_wage;
float m_hours;
// private data of CSales
float m_m;
float m_sale;
以及函数如下:
void setWage(float wg);
void setHours(float hrs);
void setmission(float m);
void setSale(float sales);
void putePay();
从Visual C++ 的除错器中,我们可以看到,上例的main 执行之后,程序拥有三个对象,
内容(我是指成员变量)分别为:
65
…………………………………………………………Page 128……………………………………………………………
从薪水说起
虚拟函数的故事要从薪水的计算说起。根据不同职员的计薪方式,我设计put ePay 函
数如下:
float CManager::putePay ()
{
return m_salary; // 经理以「固定周薪」计薪。
}
f