使用C进行面向对象编程

在 http://blog.csdn.net/kangguang/article/details/78314124 中 如果考虑要将在栈中保存的值限定在一定范围内应该怎么办呢?例如只允许0到9内的值push至栈中,该范围以外的值或是空值则不能被push至栈中。

如果重新再编写一个方法进行


bool pushWithRangeChenk(Stack *p,int val ,int min,int max)
{
    if (val<min || max<val)
    {
        return false;
    }
    return true;
}
但是这种实现方法传递的参数太多,而且每次push的时候都要传递允许的范围,非常麻烦,稍微做一下改进,在生成栈的时候将允许的范围传递过去,代码如下:



typedef struct{
    int top;
    const size_t size;
    int * const pBuf;
    
    const bool needRangeCheck;
    const int  min;
    const int  max;
} Stack;

#define newStackWithRangeCheck(buf,min,max){    \
           0,sizeof(buf)/sizeof(int),(buf),     \
           true,min,max                         \
}

static bool isRangeOk(const Stack *p,int val)
{
    return !p->needRangeCheck || (p->min<=val && val<=p->max);
}
bool push(Stack *p, int val)
{
    if (!isRangeOk(p, val) ||  isStackFull(p))
    {
        return false;
    }
    p->pBuf[p->top++] = val;
    return true;
}

  上面代码结构体里 保存了是否需要进行范围检查(needRangeCheck)的信息以及值的有效范围(min,max),并且定义了新的宏,用来生成带有范围检查功能的栈。


 int buf[10];
 Stack stack = newStackWithRangeCheck(buf, 0, 9);
注意:

   如果只有这样简单的功能,上述方法足够应付了,但是以上代码中仍然有以下问题。

  • 即使要生成的是不带范围检查功能的栈,栈内也需要保存needRangeCheck、min、max等多余的结构体成员,浪费了内存。
  • 如果还想在栈内增加其他校验功能,就必须在结构体内再增加其他成员。这样就必须在结构体内保存所有检查功能的成员,push函数也会因这些功能变得臃肿,最终导致栈越来越难以应对功能的增加。

因为结构体成员 needRangeCheck、min、max 值在isRangeOk函数中被使用,将它们作为结构体成员让所有函数都可以看到是不合适的,也就是说存在作用域污染问题,所以需要把这些成员分离出去:


typedef struct{
    const int min;
    const int max;
}Range;
    
typedef struct{
    int top;
    const size_t size;
    int * const pBuf;
    
    const Range * const pRange;
} Stack;

#define newStackWithRangeCheck(buf,pRange){     \
           0,sizeof(buf)/sizeof(int),(buf),     \
           pRange                               \
}

将范围检查分离出来的栈:


static bool isRangeOk(const Range * p,int val)
{
    return p== NULL || (p->min<=val && val<=p->max);
}
bool push(Stack *p, int val)
{
    if (!isRangeOk(p->pRange, val) ||  isStackFull(p))
    {
        return false;
    }
    p->pBuf[p->top++] = val;
    return true;
}
检查功能的通用化

  之前对栈加入了输入值上限和下限的检查功能,一般情况下,检查并不限于范围检查,例如,如果要求每次push到栈中的值都必须比上次的值大(虽然一般不会有这种要求),目前的代码还无法满足要求,但是只要将输入值检查变得更通用化就能解决这个问题

首先:将检查输入值的通用职责转移到结构体中:


#ifdef __cplusplus
extern "C"{
#endif
typedef struct Validator{
    bool (* const validator)( struct Validator * pThis,int val);//1
    void * const pData;//2
   
}Validator;
    
    
typedef struct{//3
    const int min;
    const int max;
}Range;
 
typedef struct{//4
    int previousValue;

}PreviousValue;
    
typedef struct{
    int top;
    const size_t size;
    int * const pBuf;
    
    Validator * const pValidator;
} Stack;
//5  
bool validateRange(Validator * pThis,int val);
bool validatePrevious(Validator * pThis,int val);
    
bool push(Stack *p, int val);
bool pop(Stack *p,int *pRet);
 
//6
#define rangeValidator(pRange){                 \
     validateRange,                             \
     pRange                                     \
}

#define previousValidator(pPrevious){           \
     validatePrevious,                          \
     pPrevious                                  \
}
    
    
#define newStack(buf){                          \
      0,sizeof(buf)/sizeof(int),(buf)           \
}

#define newStackWithRangeCheck(buf,pRange){     \
           0,sizeof(buf)/sizeof(int),(buf),     \
           pRange                               \
}
    
#define newStackWithValidator(buf,pValidator){  \
           0,sizeof(buf)/sizeof(int),(buf),     \
           pValidator                           \
}
    
#ifdef __cplusplus
}
#endif
 1.Validator 结构体中的第一个成员是函数指针。该函数的参数为指向Validator结构体的指针和需要校验的值,并以bool类型返回校验结果。

2.第二个成员为校验是所需要的数据。由于校验类型不同,所以需要被校验的类型也不尽相同,为了能够保存任意类型数据,这里使用了void指针。

3.如果是范围检查,则2中的void指针接受的数据为Range结构体。

4.如果是push值递增的校验 则2中的void指针接受的数据为保存上次push的值的结构体。

5.函数指针所指向的校验函数,Validator的pData成员是void指针,因此先通过类型转换取出校验时所必须的值,然后进行校验处理。

6.使得结构体的生成变得更加简单的宏。


static bool isStackFull(const Stack *p)
{
    return  p->top == p->size;
}
static bool isStackEmpty(const Stack *p)
{
    return p->top == 0;
}
bool validate(Validator * p,int val)
{
    if (!p)
    {
        return true;
    }
    return p->validator(p,val);
}

bool push(Stack *p, int val)
{
    if (!validate(p->pValidator, val) ||  isStackFull(p))
    {
        return false;
    }
    p->pBuf[p->top++] = val;
    return true;
}
bool pop(Stack *p,int *pRet)
{
    if (isStackEmpty(p))
    {
        return false;
    }
    * pRet = p->pBuf[--p->top];
    return false;
}

bool pushWithRangeChenk(Stack *p,int val ,int min,int max)
{
    if (val<min || max<val)
    {
        return false;
    }
    return true;
}

bool validateRange(Validator * pThis,int val)
{
    Range * pRange = (Range *)(pThis->pData);
    return pRange->min<=val && val<= pRange->max;
}
bool validatePrevious(Validator * pThis,int val)
{
    PreviousValue * pPrevious =(PreviousValue *)pThis->pData;
    if (val<pPrevious->previousValue)
    {
        return false;
    }
    pPrevious->previousValue = val;
    return true;
}

    //3.1
    int buf[16];
    Stack stack = newStack(buf);
    push(&stack, 123);

    //3.2
    Range  range = {0,9};
    Validator  validator = rangeValidator(&range);
    Stack stack2 = newStackWithValidator(buf, &validator);
    push(&stack2, 123);

    //3.3
    PreviousValue previous ={0};
    Validator validator2 = previousValidator(&previous);
    Stack  stack3 = newStackWithValidator(buf, &validator2);
    push(&stack3, 123);
    return 0;
   

  

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值