我建议不要使用预处理器(Ab)来尝试使C语法更像另一种更面向对象的语言。在最基本的级别上,您只需使用普通的结构作为对象,并通过指针传递它们:struct monkey{
float age;
bool is_male;
int happiness;};void monkey_dance(struct monkey *monkey){
/* do a little dance */}
要获得诸如继承和多态性之类的东西,您必须更加努力地工作。您可以通过让结构的第一个成员成为超类的实例来进行手动继承,然后可以自由地围绕指向基类和派生类的指针进行转换:struct base{
/* base class members */};struct derived{
struct base super;
/* derived class members */};struct derived d;struct base *base_ptr = (struct base *)&d;
// upcaststruct derived *derived_ptr = (struct derived *)base_ptr; // downcast
要获得多态性(即虚拟函数),可以使用函数指针和可选的函数指针表,也称为虚拟表或vtable:struct base;struct base_vtable{
void (*dance)(struct base *);
void (*jump)(struct base *, int how_high);};struct base{
struct base_vtable *vtable;
/* base members */};void base_dance(struct base *b){
b->vtable->dance(b);}void base_jump(struct base *b, int how_high){
b->vtable->jump(b, how_high);}struct derived1{
struct base super;
/* derived1 members */};void derived1_dance(struct derived1 *d){
/* implementation of derived1's dance function */}void derived1_jump(struct derived1 *d, int how_high){
/* implementation of derived 1's jump function */}/* global vtable for derived1 */struct base_vtable derived1_vtable ={
&derived1_dance, /* you might get a warning here about incompatible pointer types */
&derived1_jump /* you can ignore it, or perform a cast to get rid of it */};void derived1_init(struct derived1 *d){
d->super.vtable = &derived1_vtable;
/* init base members d->super.foo */
/* init derived1 members d->foo */}struct derived2{
struct base super;
/* derived2 members */};void derived2_dance(struct derived2 *d){
/* implementation of derived2's dance function */}void derived2_jump(struct derived2 *d, int how_high){
/* implementation of derived2's jump function */}struct base_vtable derived2_vtable ={
&derived2_dance,
&derived2_jump};void derived2_init(struct derived2 *d){
d->super.vtable = &derived2_vtable;
/* init base members d->super.foo */
/* init derived1 members d->foo */}int main(void){
/* OK! We're done with our declarations, now we can finally do some
polymorphism in C */
struct derived1 d1;
derived1_init(&d1);
struct derived2 d2;
derived2_init(&d2);
struct base *b1_ptr = (struct base *)&d1;
struct base *b2_ptr = (struct base *)&d2;
base_dance(b1_ptr); /* calls derived1_dance */
base_dance(b2_ptr); /* calls derived2_dance */
base_jump(b1_ptr, 42); /* calls derived1_jump */
base_jump(b2_ptr, 42); /* calls derived2_jump */
return 0;}
这就是你在C中做多态的方法,它不是很漂亮,但它做的是工作。在基类和派生类之间存在一些涉及指针转换的棘手问题,只要基类是派生类的第一个成员,这些问题就是安全的。多重继承要困难得多-在这种情况下,为了在第一个基类之间进行大小写,您需要根据适当的偏移量手动调整指针,这是非常棘手和容易出错的。
您可以做的另一件(棘手的)事情是在运行时更改对象的动态类型!您只需重新分配一个新的vtable指针。您甚至可以在保留其他函数的同时选择性地更改一些虚拟函数,从而创建新的混合类型。只是要小心地创建一个新的vtable,而不是修改全局vtable,否则会意外地影响到给定类型的所有对象。