四.C面向对象综合示例
1. 示例1:(缺点:继承后方法名字没统一)
之前实现了一个简单的栈 ,其重点完成了栈的核心逻辑(入栈和出栈),假设现在增加了需求,需要实现一个带检查功能的栈,即:在数据入栈之前,必须进行特定的检查,“检查通过”后才能压人栈中。检查方式可能多种多样,假定目前有以下几种检查方式:
- 范围检查:必须在特定的范围之内,比如:1 ~ 9,才视为检查通过;
- 奇偶检查:必须是奇数(或者偶数),才视为检查通过;
- 变化检查:值必须增加(比上一次的值大),才视为检查通过。
继承关系如下
基本栈struct stack代码略。
stack_with_validate.h
#ifndef __STACK_WITH_VALIDATE_H
#define __STACK_WITH_VALIDATE_H
#include "stack.h" /* 包含基类头文件 */
struct stack_with_validate {
struct stack super; /* 基类(超类) */
int(*validate) (struct stack_with_validate *p_this, int val);
};
int stack_with_validate_init(struct stack_with_validate *p_stack,
int *p_buf,
int size,
int(*validate) (struct stack_with_validate *, int));
int stack_with_validate_push(struct stack_with_validate *p_stack, int val); /* 入栈 */
int stack_with_validate_pop(struct stack_with_validate *p_stack, int *p_val); /* 出栈 */
#endif
stack_with_validate.c
#include "stack_with_validate.h"
#include "stdio.h"
int stack_with_validate_init(struct stack_with_validate *p_stack,
int *p_buf,
int size,
int(*validate) (struct stack_with_validate *, int))
{
/* 初始化基类 */
stack_init(&p_stack->super, p_buf, size);
p_stack->validate = validate;
return 0;
}
int stack_with_validate_push(struct stack_with_validate *p_stack, int val)
{
if ((p_stack->validate == NULL) || (p_stack->validate(p_stack, val) == 0)) {
return stack_push(&p_stack->super, val);
}
return -1;
}
int stack_with_validate_pop(struct stack_with_validate *p_stack, int *p_val)
{
return stack_pop(&p_stack->super, p_val);
}
stack_with_range_check.h
#ifndef __STACK_WITH_RANGE_CHECK_H
#define __STACK_WITH_RANGE_CHECK_H
#include "stack_with_validate.h" /* 包含基类头文件 */
struct stack_with_range_check {
struct stack_with_validate super; /* 基类(超类) */
int min; /* 最小值 */
int max; /* 最大值 */
};
struct stack_with_validate * stack_with_range_check_init(struct stack_with_range_check *p_stack,
int *p_buf,
int size,
int min,
int max);
#endif
stack_with_range_check.c
#include "stack_with_range_check.h"
static int __validate(struct stack_with_validate *p_this, int val)
{
struct stack_with_range_check *p_stack = (struct stack_with_range_check *)p_this;
if ((val >= p_stack->min) && (val <= p_stack->max)) {
return 0; /* 检查通过 */
}
return -1;
}
struct stack_with_validate * stack_with_range_check_init(struct stack_with_range_check *p_stack,
int *p_buf,
int size,
int min,
int max)
{
/* 初始化基类 */
stack_with_validate_init(&p_stack->super, p_buf, size, __validate);
/* 初始化子类成员 */
p_stack->min = min;
p_stack->max = max;
return &p_stack->super;
}
带范围检查的栈,主要目的就是实现“检查功能”对应的函数:__validate,并将其作为 validate 函数指针(抽象方法)的值。这里看起来也是一种继承关系,的确如此。在面向对象编程中,包含抽象方法的类通常称之为抽象类,抽象类不能直接实例化(因为其还有方法没有实现),抽象类只能被继承,且由子类实现其中定义的抽象方法。
main.c重点
#include "stack_with_validate.h"
int stack_validate_application(struct stack_with_validate *p_stack)
{
int i;
int val;
int test_data[5] = { 2, 4, 5, 3, 10 };
for (i = 0; i < 5; i++) {
if (stack_with_validate_push(p_stack, test_data[i]) != 0) {
printf("The data %d push failed!\n", test_data[i]);
}
}
printf("The pop data: ");
while (1) { /* 弹出所有数据 */
if (stack_with_validate_pop(p_stack, &val) == 0) {
printf("%d ", val);
}
else {
break;
}
}
return 0;
}
int main ()
{
int buf[20];
struct stack_with_range_check stack;
struct stack_with_validate *p_stack = stack_with_range_check_init(&stack, buf, 20, 1, 9);
stack_validate_application(p_stack);
}
初始化过程往往和实际的应用程序是分离的,也就是说,对于用户来讲,其仅会获取到一个 struct stack_with_validate *类型的指针,其指向某个“带检查功能的栈”,实际检查什么,用户可能并不需要关心,应用程序基于该类型指针编程,将使应用程序与具体检查功能无关,即使后续更换为其它检查方式,应用程序也不需要做任何改动。
2. 示例2:再细分类(类的粒度,视场景而定。依赖)
在前面的实现中,将检查功能视为栈的一种扩展(因而多处使用到了继承),检查逻辑直接在相应的扩展类中实现。这就致使检查功能与栈绑定在一起, 检查功能的实现无法独立复用。 如果要实现一个“带检查功能的队列”,同样是上述的 3 种检查逻辑, 自然而言的期望能够复用检查逻辑相关的代码。 显然,由于当前检查逻辑的实现与栈捆绑在一起,无法单独拿出来复用。
继承关系如下
validator.h
#ifndef __VALIDATOR_H
#define __VALIDATOR_H
struct validator {
int(*validate) (struct validator *p_this, int val);
};
static inline
int validator_init(struct validator *p_validator,
int(*validate) (struct validator *, int))
{
p_validator->validate = validate;
return 0;
}
static inline
int validator_validate(struct validator *p_validator, int val) /* 校验函数 */
{
if (!p_validator->validate) { /* 校验函数为空,视为无需校验 */
return 0;
}
return p_validator->validate(p_validator, val);
}
#endif
validator_range_check.h
#ifndef __VALIDATOR_RANGE_CHECK_H
#define __VALIDATOR_RANGE_CHECK_H
#include "validator.h"
struct validator_range_check {
struct validator super;
int min;
int max;
};
struct validator* validator_range_check_init(struct validator_range_check *p_validator, int min, int max);
#endif
validator_range_check.c
#include "validator_range_check.h"
static int __validate(struct validator *p_this, int val)
{
struct validator_range_check *p_stack = (struct validator_range_check *)p_this;
if ((val >= p_stack->min) && (val <= p_stack->max)) {
return 0; /* 检查通过 */
}
return -1;
}
struct validator* validator_range_check_init(struct validator_range_check *p_validator, int min, int max)
{
validator_init(&p_validator->super, __validate);
p_validator->min = min;
p_validator->max = max;
return &p_validator->super;
}
stack_with_validate.h
#ifndef __STACK_WITH_VALIDATE_H
#define __STACK_WITH_VALIDATE_H
#include "stack.h" /* 包含基类头文件 */
#include "validator.h"
struct stack_with_validate {
struct stack super; /* 基类(超类) */
struct validator *p_validator; /* 依赖 */
};
int stack_with_validate_init(struct stack_with_validate *p_stack,
int *p_buf,
int size,
struct validator *p_validator);
int stack_with_validate_push(struct stack_with_validate *p_stack, int val);
int stack_with_validate_pop(struct stack_with_validate *p_stack, int *p_val);
#endif
stack_with_validate.c
#include "stack_with_validate.h"
#include "stdio.h"
int stack_with_validate_init(struct stack_with_validate *p_stack,
int *p_buf,
int size,
struct validator *p_validator)
{
stack_init(&p_stack->super, p_buf, size);
p_stack->p_validator = p_validator;
return 0;
}
int stack_with_validate_push(struct stack_with_validate *p_stack, int val)
{
if ((p_stack->p_validator == NULL) || (validator_validate(p_stack->p_validator, val) == 0)) {
return stack_push(&p_stack->super, val);
}
return -1;
}
int stack_with_validate_pop(struct stack_with_validate *p_stack, int *p_val)
{
return stack_pop(&p_stack->super, p_val);
}
main.c
#include "stack_with_validate.h"
#include "validator_range_check.h"
#include "stdio.h"
int main()
{
int buf[20];
struct stack_with_validate stack;
struct validator_range_check validator_range_check;
/* 获取范围检查校验器 */
struct validator *p_validator = validator_range_check_init(&validator_range_check, 1, 9);
stack_with_validate_init(&stack, buf, 20, p_validator);
stack_validate_application(&stack);
return 0;
}
3. 示例3:(最终方案,虚函数,接口,抽象类)
正常的场合是,更具接口stack.h就能够编写应用app.c
stack.h
#ifndef __STACK_H
#define __STACK_H
struct stack {
int(*push) (struct stack *p_stack, int val);
int(*pop) (struct stack *p_stack, int *p_val);
};
static inline
int stack_init(struct stack *p_stack,
int(*push) (struct stack *, int),
int(*pop) (struct stack *, int *))
{
p_stack->push = push;
p_stack->pop = pop;
}
static inline
int stack_push(struct stack *p_stack, int val)
{
return p_stack->push(p_stack, val);
}
static inline
int stack_pop(struct stack *p_stack, int *p_val)
{
return p_stack->pop(p_stack, p_val);
}
#endif
app.c
#include "stack.h"
#include "stdio.h"
int stack_application(struct stack *p_stack)
{
int i;
int val;
int test_data[5] = { 2, 4, 5, 3, 10 };
for (i = 0; i < 5; i++) {
if (stack_push(p_stack, test_data[i]) != 0) {
printf("The data %d push failed!\n", test_data[i]);
}
}
printf("The pop data: ");
while (1) { /* 弹出所有数据 */
if (stack_pop(p_stack, &val) == 0) {
printf("%d ", val);
}
else {
break;
}
}
return 0;
}
以上,完全把底层和应用剥离出来
普通栈实现
stack_normal.h
#ifndef __STACK_NORMAL_H
#define __STACK_NORMAL_H
#include "stack.h"
struct stack_normal {
struct stack super;
int top; /* 栈顶 */
int *p_buf; /* 栈缓存 */
unsigned int size; /* 栈缓存的大小 */
};
struct stack * stack_normal_init(struct stack_normal *p_stack, int *p_buf, int size);
#endif
stack_normal.c
#include "stack_normal.h"
static int __push(struct stack *p_this, int val)
{
struct stack_normal *p_stack = (struct stack_normal *)p_this;
if (p_stack->top != p_stack->size) {
p_stack->p_buf[p_stack->top++] = val;
return 0;
}
return -1;
}
static int __pop(struct stack *p_this, int *p_val)
{
struct stack_normal *p_stack = (struct stack_normal *)p_this;
if (p_stack->top != 0) {
*p_val = p_stack->p_buf[--p_stack->top];
return 0;
}
return -1;
}
struct stack * stack_normal_init(struct stack_normal *p_stack, int *p_buf, int size)
{
p_stack->top = 0;
p_stack->size = size;
p_stack->p_buf = p_buf;
stack_init(&p_stack->super, __push, __pop);
return &p_stack->super;
}
maic.c
#include "stack_normal.h"
int main()
{
int buf[20];
struct stack_normal stack;
struct stack *p_stack = stack_normal_init(&stack, buf, 20);
stack_application(p_stack);
return 0;
}
检查栈实现
stack_with_validate.h
#ifndef __STACK_WITH_VALIDATE_H
#define __STACK_WITH_VALIDATE_H
#include "stack.h" /* 包含基类头文件 */
struct stack_with_validate {
struct stack super; /* 基类(超类) */
struct stack *p_normal_stack; /* 依赖于普通栈的实现 */
struct validator *p_validator;
};
struct stack * stack_with_validate_init(struct stack_with_validate *p_stack,
struct stack *p_normal_stack,
struct validator *p_validator);
#endif
stack_with_validate.c
#include "stack_with_validate.h"
#include "stdio.h"
static int __push(struct stack *p_this, int val)
{
struct stack_with_validate *p_stack = (struct stack_with_validate *)p_this;
if ((p_stack->p_validator == NULL) || (validator_validate(p_stack->p_validator, val) == 0)) {
return stack_push(p_stack->p_normal_stack, val);
}
return -1;
}
static int __pop(struct stack *p_this, int *p_val)
{
struct stack_with_validate *p_stack = (struct stack_with_validate *)p_this;
return stack_pop(p_stack->p_normal_stack, p_val);
}
struct stack * stack_with_validate_init(struct stack_with_validate *p_stack,
struct stack *p_normal_stack,
struct validator *p_validator)
{
stack_init(&p_stack->super, __push, __pop);
p_stack->p_validator = p_validator;
p_stack->p_normal_stack = p_normal_stack;
return &p_stack->super;
}
main.c
#include "stack_normal.h"
#include "stack_with_validate.h"
#include "validator_range_check.h"
int main()
{
int buf[20];
struct stack_normal stack;
struct stack_with_validate stack_with_validate;
struct validator_range_check validator_range_check;
struct stack *p_stack_normal = stack_normal_init(&stack, buf, 20);
struct validator *p_validator = validator_range_check_init(&validator_range_check, 1, 9);
struct stack *p_stack = stack_with_validate_init(&stack_with_validate,
p_stack_normal,
p_validator);
stack_application(p_stack);
return 0;
}
这里,有一个值得注意的地方,validator_range_check继承于stack,依赖于stack_normal,而不是继承于stack_normal。所以validator_range_check里面是有2套出入栈的方法的,分别在p_stack->super和p_stack->p_normal_stack上。
如果嫌弃这种办法话,validator_range_check可以直接继承stack_normal,那么需要覆盖掉push和pop方法。
两种各有各的好坏,视情况而定。