gpt4 book ai didi

c - C中的面向对象

转载 作者:太空狗 更新时间:2023-10-29 16:14:17 34 4
gpt4 key购买 nike

在 C 语言中启用某种丑陋(但可用)的面向对象的漂亮预处理器 hack(兼容 ANSI C89/ISO C90)会是什么?

我熟悉几种不同的面向对象语言,所以请不要回答“学习 C++!”之类的问题。我已经阅读了“Object-Oriented Programming With ANSI C”(注意:PDF 格式)和其他几个有趣的解决方案,但我最感兴趣的是你的:-)!


另见 Can you write object oriented code in C?

最佳答案

我建议不要使用预处理器 (ab) 来尝试使 C 语法更像另一种更面向对象的语言。在最基本的层面上,您只需使用普通结构作为对象并通过指针传递它们:

struct monkey
{
float age;
bool is_male;
int happiness;
};

void monkey_dance(struct monkey *monkey)
{
/* do a little dance */
}

要得到继承、多态之类的东西,还得下点功夫。您可以通过将结构的第一个成员作为父类(super class)的实例来进行手动继承,然后您可以随意转换指向基类和派生类的指针:

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 语言中实现多态性的方式。它并不漂亮,但可以完成工作。有一些涉及基类和派生类之间的指针转换的棘手问题,只要基类是派生类的第一个成员,这些问题就是安全的。多重继承要困难得多 - 在这种情况下,为了在第一个基类之外的基类之间进行 case,您需要根据适当的偏移量手动调整指针,这非常棘手且容易出错。

您可以做的另一件(棘手的)事情是在运行时更改对象的动态类型!您只需为它重新分配一个新的 vtable 指针。您甚至可以有选择地更改某些虚函数,同时保留其他虚函数,从而创建新的混合类型。小心创建一个新的 vtable 而不是修改全局 vtable,否则你会意外地影响给定类型的所有对象。

关于c - C中的面向对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/415452/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com