在C方向

什么是一组漂亮的预处理器黑客(兼容ANSI C89 / ISO C90),它在C中启用某种丑陋(但可用)的面向对象?

我熟悉几种不同的面向对象的语言,所以请不要回答“Learn C ++!”这样的答案。 我读过“面向对象编程与ANSI C”(当心: PDF格式 )和其他一些有趣的解决方案,但我最感兴趣的是你们:-)!


另请参阅可以在C中编写面向对象的代码吗?


C对象系统(COS)听起来很有前途(它仍然是alpha版本)。 为了简单和灵活性,它试图尽量减少可用的概念:统一的面向对象编程包括开放类,元类,属性元类,泛型,多方法,委托,所有权,异常,契约和闭包。 有一份草稿文件(PDF)描述了它。

C中的例外是在其他OO语言中发现的TRY-CATCH-FINALLY的C89实现。 它配备了测试套件和一些示例。

Laurent Deniau,这在C语言的OOP上工作很多


我建议不要使用预处理器(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;  // upcast
struct derived *derived_ptr = (struct derived *)base_ptr;  // downcast

要获得多态性(即虚拟函数),可以使用函数指针和函数指针表(也称为虚拟表或vtables):

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,否则会意外地影响给定类型的所有对象。


我曾经与一个C库一起工作,这个C库的实现方式让我觉得非常优雅。 他们用C语言编写了一种定义对象的方法,然后继承它们,使它们像C ++对象一样可扩展。 基本的想法是这样的:

  • 每个对象都有自己的文件
  • 公用函数和变量在.h文件中为一个对象定义
  • 私有变量和函数只位于.c文件中
  • 为了“继承”一个新的结构,该结构的第一个成员是要继承的对象
  • 继承很难描述,但基本上是这样的:

    struct vehicle {
       int power;
       int weight;
    }
    

    然后在另一个文件中:

    struct van {
       struct vehicle base;
       int cubic_size;
    }
    

    然后,你可以在记忆中创建一辆面包车,并被代码使用,只知道车辆:

    struct van my_van;
    struct vehicle *something = &my_van;
    vehicle_function( something );
    

    它运行得很漂亮,.h文件定义了你应该能够对每个对象做什么。

    链接地址: http://www.djcxy.com/p/79151.html

    上一篇: orientation in C

    下一篇: Which languages are used for safety