How can I simulate OO-style polymorphism in C?

2019-01-01 06:41发布

Is there a way to write OO-like code in the C programming language?


See also:

Found by searching on "[c] oo".

9条回答
ら面具成の殇う
2楼-- · 2019-01-01 07:10

From Wikipedia: In programming languages and type theory, polymorphism (from Greek πολύς, polys, "many, much" and μορφή, morphē, "form, shape") is the provision of a single interface to entities of different types.

So I would say the only way to implement it in C is by using variadic arguments along with some (semi)automatic type info management. For example in C++ you can write (sorry for trivialness):

void add( int& result, int a1, int a2 );
void add( float& result, float a1, float a2 );
void add( double& result, double a1, double a2 );

In C, among other solutions, the best you can do is something like this:

int int_add( int a1, int a2 );
float float_add( float a1, fload a2 );
double double_add( double a1, double a2 );

void add( int typeinfo, void* result, ... );

Then you need:

  1. to implement the "typeinfo" with enums/macros
  2. to implement the latter function with stdarg.h stuff
  3. to say goodbye to C static type checking

I am almost sure that any other implementation of polymorphism should look much like this very one. The above answers, instead, seems to try to address inheritance more than polymorphism!

查看更多
临风纵饮
3楼-- · 2019-01-01 07:11
#include <stdio.h>

typedef struct {
    int  x;
    int z;
} base;

typedef struct {
    base;
    int y;
    int x;
} derived;

void function_on_base( base * a) // here I can pass both pointers to derived and to base
{
    printf("Class base [%d]\n",a->x);
    printf("Class base [%d]\n",a->z);
}
void function_on_derived( derived * b) // here I must pass a pointer to the derived class
{
    printf("Class derived [%d]\n",b->y);
    printf("Class derived [%d]\n",b->x);
}

int main()
{
    derived d;
    base b;
    printf("Teste de poliformismo\n");

    b.x = 2;
    d.y = 1;
    b.z = 3;
    d.x = 4;
    function_on_base(&b);
    function_on_base(&d);
    function_on_derived(&b);
    function_on_derived(&d);
    return 0;
}

The output was:

Class base [3]
Class base [1]
Class base [4]
Class derived [2]
Class derived [3]
Class derived [1]
Class derived [4]

so it works, its a polymorphic code.

UncleZeiv explained about it at the beginning.

查看更多
萌妹纸的霸气范
4楼-- · 2019-01-01 07:15

Appendix B of the article Open Reusable Object Models, by Ian Piumarta and Alessandro Warth of VPRI is an implementation of an Object model in GNU C, about 140 lines of code. It's a fascinating read !

Here's the uncached version of the macro that sends messages to objects, using a GNU extension to C (statement expression):

struct object;

typedef struct object *oop; 
typedef oop *(*method_t)(oop receiver, ...);

//...

#define send(RCV, MSG, ARGS...) ({ \ 
    oop r = (oop)(RCV); \ 
    method_t method = _bind(r, (MSG)); \ 
    method(r, ##ARGS); \ 
}) 

In the same doc, have a look at the object, vtable, vtable_delegated and symbol structs, and the _bind and vtable_lookup functions.

Cheers!

查看更多
刘海飞了
5楼-- · 2019-01-01 07:15

The first C++ compiler ("C with classes") would actually generate C code, so that's definitely doable.

Basically, your base class is a struct; derived structs must include the base struct at the first position, so that a pointer to the "derived" struct will also be a valid pointer to the base struct.

typedef struct {
   data member_x;
} base;

typedef struct {
   struct base;
   data member_y;
} derived;

void function_on_base(struct base * a); // here I can pass both pointers to derived and to base

void function_on_derived(struct derived * b); // here I must pass a pointer to the derived class

The functions can be part of the structure as function pointers, so that a syntax like p->call(p) becomes possible, but you still have to explicitly pass a pointer to the struct to the function itself.

查看更多
几人难应
6楼-- · 2019-01-01 07:16

The file functions fopen, fclose, fread are examples of OO code in C. Instead of the private data in class, they work on the FILE structure which is used to encapsulate the data and the C functions acts as an member class functions. http://www.amazon.com/File-Structures-Object-Oriented-Approach-C/dp/0201874016

查看更多
大哥的爱人
7楼-- · 2019-01-01 07:19

I looked at everyone elses' answers and came up with this:

#include <stdio.h>

typedef struct
{
    int (*get)(void* this);
    void (*set)(void* this, int i);
    int member;

} TheClass;

int Get(void* this)
{
    TheClass* This = (TheClass*)this;
    return This->member;
}

void Set(void* this, int i)
{
    TheClass* This = (TheClass*)this;
    This->member = i;
}

void init(TheClass* this)
{
    this->get = &Get;
    this->set = &Set;
}

int main(int argc, char **argv)
{
    TheClass name;
    init(&name);
    (name.set)(&name, 10);
    printf("%d\n", (name.get)(&name));
    return 0;
}

I hope that answers some questions.

查看更多
登录 后发表回答