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


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


当前回答

这本书读起来很有趣。我自己也在思考同样的问题,思考这个问题的好处是:

Trying to imagine how to implement OOP concepts in a non-OOP language helps me understand the strengths of the OOp language (in my case, C++). This helps give me better judgement about whether to use C or C++ for a given type of application -- where the benefits of one out-weighs the other. In my browsing the web for information and opinions on this I found an author who was writing code for an embedded processor and only had a C compiler available: http://www.eetimes.com/discussion/other/4024626/Object-Oriented-C-Creating-Foundation-Classes-Part-1

在他的案例中,用普通C语言分析和调整面向对象的概念是一种有效的追求。他似乎愿意牺牲一些面向对象的概念,因为尝试用C语言实现它们会带来性能开销。

我得到的教训是,是的,在某种程度上它是可以做到的,是的,有一些很好的理由去尝试。

In the end, the machine is twiddling stack pointer bits, making the program counter jump around and calculating memory access operations. From the efficiency standpoint, the fewer of these calculations done by your program, the better... but sometimes we have to pay this tax simply so we can organize our program in a way that makes it least susceptible to human error. The OOP language compiler strives to optimize both aspects. The programmer has to be much more careful implementing these concepts in a language like C.

其他回答

你可能会发现,查看苹果的Core Foundation api集文档会很有帮助。它是一个纯C API,但是许多类型都被桥接到Objective-C对象等价物上。

看看Objective-C本身的设计也会有帮助。它与c++有点不同,对象系统是根据C函数定义的,例如objc_msg_send用于调用对象上的方法。编译器将方括号语法转换为这些函数调用,因此您不必了解它,但考虑到您的问题,您可能会发现了解它在底层是如何工作的很有用。

看看GObject。它应该是C语言中的OO,是您正在寻找的东西的一个实现。如果你真的想要面向对象,那就使用c++或其他面向对象语言。如果您习惯了处理OO语言,那么GObject有时真的很难使用,但是像其他东西一样,您会习惯它的约定和流程。

我有点晚了,但我想分享我在这个主题上的经验:我这些天在使用嵌入式的东西,我唯一的(可靠的)编译器是C,所以我想在我用C编写的嵌入式项目中应用面向对象的方法。

到目前为止,我看到的大多数解决方案都大量使用类型转换,因此我们失去了类型安全:如果你犯了错误,编译器不会帮助你。这是完全不能接受的。

我的要求是:

尽可能避免类型转换,这样我们就不会失去类型安全; 多态:我们应该能够使用虚方法,类的用户不应该知道某个特定的方法是否是虚的; 多重继承:我不经常使用它,但有时我确实希望某个类实现多个接口(或扩展多个超类)。

我在本文中详细解释了我的方法:C语言中的面向对象编程;另外,还有一个工具可以自动生成基类和派生类的样板代码。

我已经研究这个一年了

由于GObject系统很难用纯C语言使用,所以我尝试编写一些不错的宏来简化C语言的OO风格。

#include "OOStd.h"

CLASS(Animal) {
    char *name;
    STATIC(Animal);
    vFn talk;
};
static int Animal_load(Animal *THIS,void *name) {
    THIS->name = name;
    return 0;
}
ASM(Animal, Animal_load, NULL, NULL, NULL)

CLASS_EX(Cat,Animal) {
    STATIC_EX(Cat, Animal);
};
static void Meow(Animal *THIS){
    printf("Meow!My name is %s!\n", THIS->name);
}

static int Cat_loadSt(StAnimal *THIS, void *PARAM){
    THIS->talk = (void *)Meow;
    return 0;
}
ASM_EX(Cat,Animal, NULL, NULL, Cat_loadSt, NULL)


CLASS_EX(Dog,Animal){
    STATIC_EX(Dog, Animal);
};

static void Woof(Animal *THIS){
    printf("Woof!My name is %s!\n", THIS->name);
}

static int Dog_loadSt(StAnimal *THIS, void *PARAM) {
    THIS->talk = (void *)Woof;
    return 0;
}
ASM_EX(Dog, Animal, NULL, NULL, Dog_loadSt, NULL)

int main(){
    Animal *animals[4000];
    StAnimal *f;
    int i = 0;
    for (i=0; i<4000; i++)
    {
        if(i%2==0)
            animals[i] = NEW(Dog,"Jack");
        else
            animals[i] = NEW(Cat,"Lily");
    };
    f = ST(animals[0]);
    for(i=0; i<4000; ++i) {
        f->talk(animals[i]);
    }
    for (i=0; i<4000; ++i) {
        DELETE0(animals[i]);
    }
    return 0;
}

这是我的项目网站(我没有足够的时间写en。Doc,不过中文的Doc要好得多)。

东方海外海湾合作委员会

似乎人们正在尝试用C来模仿c++风格。我的观点是,用C来做面向对象的编程实际上就是做面向结构的编程。但是,您可以实现后期绑定、封装和继承等功能。对于继承,在子结构中显式地定义一个指向基结构的指针,这显然是一种多重继承。你还需要确定你的

//private_class.h
struct private_class;
extern struct private_class * new_private_class();
extern int ret_a_value(struct private_class *, int a, int b);
extern void delete_private_class(struct private_class *);
void (*late_bind_function)(struct private_class *p);

//private_class.c
struct inherited_class_1;
struct inherited_class_2;

struct private_class {
  int a;
  int b;
  struct inherited_class_1 *p1;
  struct inherited_class_2 *p2;
};

struct inherited_class_1 * new_inherited_class_1();
struct inherited_class_2 * new_inherited_class_2();

struct private_class * new_private_class() {
  struct private_class *p;
  p = (struct private_class*) malloc(sizeof(struct private_class));
  p->a = 0;
  p->b = 0;
  p->p1 = new_inherited_class_1();
  p->p2 = new_inherited_class_2();
  return p;
}

    int ret_a_value(struct private_class *p, int a, int b) {
      return p->a + p->b + a + b;
    }

    void delete_private_class(struct private_class *p) {
      //release any resources
      //call delete methods for inherited classes
      free(p);
    }
    //main.c
    struct private_class *p;
    p = new_private_class();
    late_bind_function = &implementation_function;
    delete_private_class(p);

用c_compiler main.c inherited_class_1编译。obj inherited_class_2。obj private_class.obj。

因此,我的建议是坚持使用纯C风格,不要试图强行采用c++风格。此外,这种方式也有助于以一种非常干净的方式构建API。