直截了当,我明白 ANSI C 不是一种面向对象的编程语言。我想学习如何使用 c 应用特定的 oo 技术。
例如,我想创建几个音频效果类,它们都具有相同的函数名称但这些函数的实现不同。
如果我用更高级的语言制作它,我会先编写一个接口(interface),然后再实现它。
AudioEffectInterface
-(float) processEffect
DelayClass
-(float) processEffect
{
// do delay code
return result
}
FlangerClass
-(float) processEffect
{
// do flanger code
return result
}
-(void) main
{
effect= new DelayEffect()
effect.process()
effect = new FlangerEffect()
effect.process()
}
如何使用 C 实现这种灵 active ?
最佳答案
可以通过三种不同的方式在 C 语言中实现多态性:
编码出来
在基类函数中,只需在类类型 ID 上切换
即可调用专用版本。一个不完整的代码示例:typedef enum classType { CLASS_A, CLASS_B } classType; typedef struct base { classType type; } base; typedef struct A { base super; ... } A; typedef struct B { base super; ... } B; void A_construct(A* me) { base_construct(&me->super); super->type = CLASS_A; } int base_foo(base* me) { switch(me->type) { case CLASS_A: return A_foo(me); case CLASS_B: return B_foo(me); default: assert(0), abort(); } }
当然,对于大类来说,这是乏味的。
在对象中存储函数指针
您可以通过为每个成员函数使用函数指针来避免 switch 语句。同样,这是不完整的代码:typedef struct base { int (*foo)(base* me); } base; //class definitions for A and B as above int A_foo(base* me); void A_construct(A* me) { base_construct(&me->super); me->super.foo = A_foo; }
现在,调用代码就可以了
base* anObject = ...; (*anObject->foo)(anObject);
或者,您可以按照以下方式使用预处理器宏:
#define base_foo(me) (*me->foo)(me)
请注意,这会对表达式
me
求值两次,所以这确实是个坏主意。这可能是固定的,但这超出了这个答案的范围。使用虚表
由于一个类的所有对象共享同一组成员函数,它们都可以使用相同的函数指针。这非常接近 C++ 在幕后所做的事情:typedef struct base_vtable { int (*foo)(base* me); ... } base_vtable; typedef struct base { base_vtable* vtable; ... } base; typedef struct A_vtable { base_vtable super; ... } A_vtable; //within A.c int A_foo(base* super); static A_vtable gVtable = { .foo = A_foo, ... }; void A_construct(A* me) { base_construct(&me->super); me->super.vtable = &gVtable; };
同样,这允许用户代码进行分派(dispatch)(使用一个额外的间接寻址):
base* anObject = ...; (*anObject->vtable->foo)(anObject);
您应该使用哪种方法取决于手头的任务。基于 switch
的方法很容易为两个或三个小类快速启动,但对于大类和层次结构来说却很笨拙。第二种方法的扩展性更好,但由于函数指针重复,因此会产生大量空间开销。 vtable 方法需要相当多的额外结构并引入更多间接(这使得代码更难阅读),但肯定是复杂类层次结构的方法。
关于c - OOP 和 C 中的接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6304794/