C中的实例级抽象

时间:2012-08-19 21:44:32

标签: c unit-testing design-patterns function-pointers instance-variables

我不是C专家。我的CS1&大学2天。我已经在这里和那里做了一点C ++,但它已经有一段时间了。所以我要问的是正确的模式来解决我所感知的问题。

我决定接受一个相当雄心勃勃的挑战,我在C中做这件事。我(重新)学习的东西之一是C中的不同抽象技术与我以前在更高级别中使用的抽象技术语言。我遇到的问题,并询问,特别是与测试和功能有关。

例如,我有两个函数fg,如果某些条件为真,f会调用g

void f(object* obj) {
  // ...
  if(obj->state)
    g(obj);
  // ...
}

我需要验证g实际上是被调用的,但我也不想实际执行它,因为它可以执行各种其他操作。这通常可以通过接口或抽象类或继承在更高级别的语言中解决。但是在C中我没有这些技术。

事实上,我能想到的唯一解决这个问题的方法是利用函数指针。我不应该直接调用g,而是应该添加一个指向object的指针,使其具有指向g的指针,我可以用指向测试中不同函数的指针替换它。 / p>

typedef struct object {
  int state;
  void (*g)(object* obj);
} object;

void f(object* obj) {
  // ...
  if(obj->state)
    obj->g(obj);
  // ...
}

然后通常我只是在分配g的实例时指向g但是在我的测试中我将obj-> g指向另一个函数,一个仅仅验证传入值并注意到它实际上被称为。

这是我现在的想法,但我不确定它是否是解决此问题的正确C-ish方法。希望我的描述能说明我遇到的问题,但我真正想知道的是如何最好地处理它。

在C中解决此问题的推荐设计模式是什么?

2 个答案:

答案 0 :(得分:1)

如果您要更改g的不同来电中调用的f函数,可能应将g作为参数传递给f

typedef void (*gFunc)(object* obj);

void f(object *obj, gFunc g) {
    ...
    if (obj->state) {
        g(obj);
    }
    ...
}

如果您不想弄乱f的功能签名,可以定义f版本来调用上述实现:

void gNormal(object* obj);           //normal implementation of g
void gTest(object* obj);             //test version of g

void fGeneral(object* obj, gFunc g); //general implementation of f as above

void fNormal(object* obj)            
{
    fGeneral(obj, &gNormal);         //use the default version of g
}

无论您选择此方法还是使函数指针g成为对象的成员,从语言的角度来看可能大致相同 - 您需要考虑对您的对象结构更有意义的内容。 / p>

然后,如果你做了很多这样的事情,也许你应该使用面向对象的语言!

答案 1 :(得分:0)

如果您在编译时知道是否要进入测试用例,则可以通过预处理器宏控制两种不同的g实现,如下所示:

#ifdef TESTING

    int g() { // implement test version here }

#else

    int g() { // implement real version here }

#endif

如果您只在编译时知道,可以以相同的方式使用全局变量,但两个实现都在相同的函数定义中:

 int g() {
     if (gTesting) {
         // implement test version here
     }
     else {
         // implement real version here
     }
 }