四.C面向对象综合示例(C面向对象开发)

本文通过三个逐步深入的示例,展示了如何在C语言中运用面向对象思想实现带有验证功能的栈,包括继承、抽象类、接口等概念的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

四.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方法。
两种各有各的好坏,视情况而定。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值