简体   繁体   English

C作为面向对象的语言

[英]C as an object oriented language

Could you suggest a syntax for the C language to use it in a similar way than an object-oriented language? 您是否可以建议C语言的语法以与面向对象语言类似的方式使用它? I know that they cannot be the same and that some keywords aren't present in C, but I'm wondering if there is a way to take advantage of certain aspects (like inheritance) even in a C program. 我知道它们不能相同,并且C中没有一些关键字,但我想知道是否有办法利用某些方面(如继承),即使在C程序中也是如此。

You can implement polymorphism with regular functions and virtual tables (vtables). 您可以使用常规函数和虚拟表(vtable)实现多态性。 Here's a pretty neat system that I invented (based on C++) for a programming exercise: 这是一个非常简洁的系统,我发明了(基于C ++)进行编程练习: 替代文字
(source: goblin.tkk.fi ) (来源: goblin.tkk.fi

The constructors allocate memory and then call the class' init function where the memory is initialized. 构造函数分配内存,然后调用类初始化内存的init函数。 Each init function should also contain a static vtable struct that contains the virtual function pointers (NULL for pure virtual). 每个init函数还应包含一个静态vtable结构,其中包含虚函数指针(纯虚拟的NULL)。 Derived class init functions call the superclass init function before doing anything else. 派生类init函数在执行任何其他操作之前调用超类init函数。

A very nice API can be created by implementing the virtual function wrappers (not to be confused with the functions pointed to by the vtables) as follows (add static inline in front of it, if you do this in the header): 通过实现虚函数包装器(不要与vtables指向的函数混淆)可以创建一个非常好的API,如下所示(如果在标题中执行此操作,则在其前面添加static inline ):

int playerGuess(Player* this) { return this->vtable->guess(this); }

Single inheritance can be done by abusing the binary layout of a struct: 单继承可以通过滥用结构的二进制布局来完成: 替代文字
(source: goblin.tkk.fi ) (来源: goblin.tkk.fi

Notice that multiple inheritance is messier as then you often need to adjust the pointer value when casting between types of the hierarchy. 请注意,多重继承更加混乱,因为在层次结构类型之间进行转换时,通常需要调整指针值。

Other type-specific data can be added to the virtual tables as well. 其他类型特定的数据也可以添加到虚拟表中。 Examples include runtime type info (eg type name as a string), linking to superclass vtable and the destructor chain. 示例包括运行时类型信息(例如,类型名称作为字符串),链接到超类vtable和析构函数链。 You probably want virtual destructors where derived class destructor demotes the object to its super class and then recursively calls the destructor of that and so on, until the base class destructor is reached and that finally frees the struct. 您可能需要虚拟析构函数,其中派生类析构函数将对象降级为其超类,然后递归调用它的析构函数,依此类推,直到到达基类析构函数并最终释放结构。

There is the GObject library : GObject库

The GLib Object System, or GObject, is a free software library (covered by the LGPL) that provides a portable object system and transparent cross-language interoperability. GLIB对象系统(或称GObject)是一个免费软件库(由LGPL提供),它提供了一个便携式对象系统和透明的跨语言互操作性。 GObject is designed for use both directly in C programs and through bindings to other languages. GObject旨在直接在C程序中使用,也可以通过绑定到其他语言。

The traditional solution is the function pointer struct. 传统的解决方案是函数指针结构。 I emphasize traditional. 我强调传统。 I can tell you what sort of code I wrote in PL/I and C years ago, but I don't claim to speak for the state of the 'art' if you can call this art. 我可以告诉你我在PL / I和C年前写过的代码是什么类型,但如果你可以称之为艺术,我并不会主张代表“艺术”的状态。

There are many variations on this, and the below is a bit of a compromise. 这有很多变化,下面是一个妥协。

struct SortOfAnAbstractClass {
   int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3);
   void (*function2)(SortOfAnAbstractClass* this, char *arg);
};

struct SortOfDerived {
   struct SortOfAnAbstractClass base;
   int instanceVariable1;
};

SortOfAnAbstractClass getMeOne() {
     SortOfDerived *d = malloc(sizeof SortOfDerived);
     memset(d, 0, sizeof SortOfDerived);
     d->function1 = myf1;
     d->function2 = myf2;
     return &d->base;
};

and then 'myf1' and 'myf2' cast their 'this' parameters and go to town. 然后'myf1'和'myf2'投出'this'参数然后去城里。 You can extend this to look ever more like a full virtual dispatch. 您可以将其扩展为更完整的虚拟调度。

Another common variation from the mists of time: 时间迷雾的另一个常见变化:

struct SortOfAClass {
   void *creatorInfo;
   int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3);
   void (*function2)(SortOfAnAbstractClass* this, char *arg);
};

In this variation, there's no inheritance by inclusion. 在这个变体中,包含没有继承。 The derived classes each put their private state into their own object in creatorInfo. 派生类每个都将其私有状态放入creatorInfo中自己的对象中。

看一下GObject库: http//library.gnome.org/devel/gobject/2.22/

There are many variations to doing OO programming in C. The way I prefer to do it is to define one class per a header file. 在C中进行OO编程有很多变化。我喜欢这样做的方法是为每个头文件定义一个类。 You'll notice a constructor new_testclass() which just initializes your function pointers and returns a pointer to an allocated class/struct. 你会注意到一个构造函数new_testclass() ,它只是初始化你的函数指针并返回一个指向已分配的类/结构的指针。 Also any function takes pointer to the class in the first parameter (something c++ does, but conceals). 此外,任何函数都会在第一个参数中获取指向该类的指针(c ++会这样做,但会隐藏)。

testclass.h testclass.h

#ifndef MALLOC_H
    #include<malloc.h>
#endif
struct _testclass 
{
    int a;
    int b;
    int (*sum)(struct _testclass *obj);
};

typedef struct _testclass testclass;

int f_sum (testclass *obj)
{
    return obj->a + obj->b;
}

testclass* new_testclass()
{
    testclass *temp;
    temp = (testclass*)malloc(sizeof(testclass));
    temp->sum = &f_sum;
    return temp;
}

Then you can simply use it. 然后你可以简单地使用它。

testclass.c testclass.c

#include <stdio.h>
#include "testclass.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int result;
    testclass *testclass1;
    testclass1 = new_testclass();
    testclass1->a = 5;
    testclass1->b = 8;
    result = testclass1->sum(testclass1);
    printf("%d\n",result);
    free(testclass1);
    return 0;
}

Of course there are several important aspects of object oriented programming missing here, but this provides a simple method for basic abstraction. 当然,这里缺少面向对象编程的几个重要方面,但这提供了一种简单的基本抽象方法。 I'd imagine inheritance would require some kind of funky preprocessor trick if it could be done at all. 我认为继承需要某种时髦的预处理器技巧,如果它可以完成的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM