开发中虚函数应用,大大减少开发时间
法和乘法,因此可以将它们的共性包含在BinNode中,可变性分别包含在AddNode和MultNode中。
其实输入操作数同样可以视为计算,因此NumNode和BinNode的共性也是计算,不妨将它们的共性上移到Node抽象类中。
显然,基于面向对象的C编程,则表达式算术树的所有结点都是从类Node继承的子类,Node的直系后代为NumNode和BinNode,NumNode表示一个数,BinNode表示一个二元运算,然后再从BinNode派生两个类:AddNode和MultNode。
如图 4.7所示展示了类的层次性,它们是一种"is-a"的抽象层次结构,子类AddNode和MultNode重新定义了BinNode和Node基类的结构和行为。基类代表了一般化的抽象,子类代表了特殊的抽象。虽然抽象类Node或BinNode不能实例化,只能作为其它类的父类,但NumNode、AddNode和MultNode子类是可以实例化的。
图 4.7 结点的类层次
Node抽象类的定义如下:
1 typedef struct _Node{
2 double (*nodeCalc)(struct _Node *pThis);
3 }Node;
除了Node之外,每个子类都要实现自己的nodeCalc计算方法,并返回一个作为计算结点值的双精度数。即:
1 typedef struct _NumNode{
2 Node isa;
3 double _num;
4 }NumNode;
5
6 typedef struct _BinNode{
7 Node isa;
8 Node *_pLeft;
9 Node *_pRight;
10 }BinNode;
11
12 typedef struct _AddNode{
13 BinNode isa;
14 }AddNode;
15
16 typedef struct _MultNode{
17 BinNode isa;
18 }MultNode;
其中的NumNode结点是从Node分出来的,_num表示数值。BinNode也是从Node分出来的,_pLeft和_pRight分别为指向左子树和右子树的指针,而AddNode和MultNode又是从BinNode分出来的。
此前,针对继承和多态框架,使用了一种称为静态的初始化范型。在这里,将使用动态内存分配初始化范型处理继承和多态框架。
3.建立接口
由于对象不同,因此动态分配内存的方式不一样,但其共性是——不再使用某个对象时,释放动态内存的方法是一样,因此还需要添加一个node_cleanup()函数,这是通过free()实现的,详见程序清单 4.15。
程序清单 4.15 表达式算术树的接口(CalcTree1.h)
1 #pragma once
2 typedef struct _Node Node;
3 typedef double (*node_calc_t)(Node *pThis);
4 typedef void (*node_cleanup_t)(Node *pThis);
5 struct _Node{
6 node_calc_t node_calc;
7 node_cleanup_t node_cleanup;
8 };
9
10 typedef struct _NumNode{
11 Node isa;
12 double _num;
13 }NumNode;
14
15 typedef struct _BinNode{
16 Node isa;
17 Node *_pLeft;
18 Node *_pRight;
19 }BinNode;
20
21 typedef struct _AddNode{
22 BinNode isa;
23 }AddNode;
24
25
- 面向对象编程——虚函数(09-20)
- 电源软启动的实用设计技巧(07-16)
- 周立功:动态分布内存——malloc()函数与calloc()函数(07-22)
- 周立功“程序设计与数据结构”:深度解剖动态分布内存的free()函数与realloc()函数(07-25)
- 周立功教你学程序设计技术:做好软件模块的分层设计,回调函数要这样写(07-30)
- 周立功教你学C语言编程:教你数组是如何保存指针的(07-31)