用C编写面向对象代码有哪些方法?特别是在多态性方面。


另请参阅此堆栈溢出问题C中的面向对象。


当前回答

添加一点OOC代码:

#include <stdio.h>

struct Node {
    int somevar;
};

void print() {
    printf("Hello from an object-oriented C method!");
};

struct Tree {
    struct Node * NIL;
    void (*FPprint)(void);
    struct Node *root;
    struct Node NIL_t;
} TreeA = {&TreeA.NIL_t,print};

int main()
{
    struct Tree TreeB;
    TreeB = TreeA;
    TreeB.FPprint();
    return 0;
}

其他回答

哪些文章或书籍适合在C语言中使用面向对象的概念?

Dave Hanson的《C接口与实现》在封装和命名方面非常出色,在函数指针的使用方面也非常出色。Dave没有尝试模拟继承。

是的,但我从未见过有人尝试用C实现任何类型的多态性。

既然你说的是多态性,那么是的,你可以,我们在c++出现之前几年就已经在做这类事情了。

基本上,你使用一个结构体来保存数据和一个函数指针列表,以指向该数据的相关函数。

因此,在一个通信类中,你会有一个打开、读、写和关闭调用,它将被维护为结构中的四个函数指针,与对象的数据一起,类似于:

typedef struct {
    int (*open)(void *self, char *fspec);
    int (*close)(void *self);
    int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
    int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
    // And data goes here.
} tCommClass;

tCommClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;

tCommClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;

当然,上面的那些代码段实际上是在诸如rs232Init()这样的“构造函数”中。

当你“继承”这个类时,你只需要改变指针指向你自己的函数。每个调用这些函数的人都会通过函数指针来做,给你你的多态性:

int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");

有点像手动虚表。

你甚至可以通过将指针设置为NULL来创建虚拟类——这与c++的行为略有不同(运行时的核心转储而不是编译时的错误)。

下面是一段演示它的示例代码。首先是顶级类结构:

#include <stdio.h>

// The top-level class.

typedef struct sCommClass {
    int (*open)(struct sCommClass *self, char *fspec);
} tCommClass;

然后我们有TCP '子类'的函数:

// Function for the TCP 'class'.

static int tcpOpen (tCommClass *tcp, char *fspec) {
    printf ("Opening TCP: %s\n", fspec);
    return 0;
}
static int tcpInit (tCommClass *tcp) {
    tcp->open = &tcpOpen;
    return 0;
}

HTTP也是一样:

// Function for the HTTP 'class'.

static int httpOpen (tCommClass *http, char *fspec) {
    printf ("Opening HTTP: %s\n", fspec);
    return 0;
}
static int httpInit (tCommClass *http) {
    http->open = &httpOpen;
    return 0;
}

最后是一个测试程序来展示它的作用:

// Test program.

int main (void) {
    int status;
    tCommClass commTcp, commHttp;

    // Same 'base' class but initialised to different sub-classes.

    tcpInit (&commTcp);
    httpInit (&commHttp);

    // Called in exactly the same manner.

    status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
    status = (commHttp.open)(&commHttp, "http://www.microsoft.com");

    return 0;
}

这将产生输出:

Opening TCP: bigiron.box.com:5000
Opening HTTP: http://www.microsoft.com

你可以看到不同的函数被调用,取决于子类。

如果您确信面向对象的方法对于您正在尝试解决的问题更优越,那么为什么还要尝试使用非面向对象的语言来解决它呢?看来你用错工具了。使用c++或其他面向对象的C语言变体。

如果你问这个问题是因为你要开始在一个已经存在的用C编写的大型项目上编写代码,那么你不应该试图将你自己的(或其他人的)OOP范式强加到项目的基础设施中。遵循项目中已经存在的指导方针。一般来说,干净的api和独立的库和模块将有助于实现干净的面向对象的设计。

如果,在所有这些之后,你真的打算做OOP C,请阅读这篇文章(PDF)。

面向对象的C,可以做到,我在韩国看过这种类型的代码,这是我多年来见过的最可怕的怪物(这是去年(2007年)我看到的代码)。 所以,是的,这是可以做到的,是的,人们曾经这样做过,甚至在这个时代仍然这样做。但我还是推荐c++或Objective-C,这两种语言都起源于C,目的是用不同的范式提供面向对象。