C中的OOP,实现和bug

我正在尝试在C中探索OOP。但我是一个C n00b并且想要选择stackoverflow的精彩大脑:)

我的代码如下:

#include  #include  typedef struct speaker { void (*say)(char *msg); } speaker; void say(char *dest) { printf("%s",dest); } speaker* NewSpeaker() { speaker *s; s->say = say; return s; } int main() { speaker *s = NewSpeaker(); s->say("works"); } 

但是我从这里得到了一个段落错误,但是如果我删除所有的args并使其无效,我可以让它正常工作。 我目前的代码有什么问题?

也。 虽然这在C中实现了一种forms的对象,但我正在尝试使用inheritance,甚至覆盖/重载方法来进一步实现它。 您认为我怎么能实现这样的?

谢谢!

在您的代码中, NewSpeaker()实际上并不创建“新”扬声器。 您需要使用内存分配函数,如malloccalloc

 speaker* NewSpeaker() { speaker *s = malloc(sizeof(speaker)); s->say = say; return s; } 

如果没有从malloc的返回值中分配值,则s被初始化为堆栈上的垃圾,因此是段错误。

首先,正如已经指出的那样,您无法在“NewSpeaker”中为“speaker”对象分配内存。 如果没有不必要的混乱,它将如下所示

 speaker* NewSpeaker(void) { speaker *s = malloc(sizeof *s); s->say = say; return s; } 

注意,malloc的结果没有强制转换,’sizeof’参数中没有类型名称,函数参数列表声明为’(void)’,而不仅仅是’()’。

其次,如果您希望能够创建“扬声器”类型的非动态对象,您可能希望首先提供就地初始化函数,然后从那里继续

 speaker* InitSpeaker(speaker* s) { assert(s != NULL); s->say = say; return s; } speaker* NewSpeaker(void) { void *raw = malloc(sizeof(speaker)); return raw != NULL ? InitSpeaker(raw) : NULL; } 

最后,如果您真的想要创建类似虚拟C ++方法的东西,则需要为每个方法提供一个’this’参数(以便访问对象的其他成员)。 所以它应该看起来像

 typedef struct speaker { void (*say)(struct speaker *this, char *msg); } speaker; void say(speaker *this, char *dest) { printf("%s",dest); } 

当然,这需要您在每次调用“方法”时传递相应的参数,但是没有办法解决这个问题。

另外,我希望你知道你的“类”只需要“方法”指针“虚拟方法”。 普通(非虚拟)方法不需要这样的指针。

最后,“传统的”C ++类实现不会在类的每个实例中存储虚方法指针。 相反,它们被放置在一个单独的表(VMT)中,指向该表的指针被添加到每个实例中。 这节省了大量内存。 这个BTW在实现inheritance时特别有意义。

您可以通过将父类结构嵌入子类结构的顶部来实现inheritance。 这样您就可以安全地从子类转换为父类。 这是一篇关于在C中实现OOfunction的文章 。如果您想要一个现有的解决方案,或者只是想了解更多关于实现OO的方法,请查看GObject库 。