Daveman
Daveman

Reputation: 1096

How to avoid the "self" parameter in C?

I was just playing arround with C. Here is some kind of "class" i made:

typedef struct test{
    int x;
    int y;
    int(*mul)(test *);

} mult;

int testMul(test *t){
    return t->x * t->y;
}

mult newTest(int x_in, int y_in){
    mult tmp;
    tmp.x = x_in;
    tmp.y = y_in;
    tmp.mul = &testMul;
    return tmp;
}

If I want to use the mul() "method", I do it like this:

mult a = newTest(2,6);
a.mul(&a); //12

Is there some clever way to avoid the &a param while still having access the struct-Params inside the mul() function?

Upvotes: 1

Views: 222

Answers (3)

Marco
Marco

Reputation: 7287

Sadly, there is no clean way to do this, but you can`t avoid passing the reference to the function because functions are stateless.

But you could make it like this to make it look nicer:

(This goes implementation):

struct test {
    int x;
    int y;
};

test_t _test_create(int const x, int const y)
{
    test_t t = malloc(sizeof(* t));
    if (!t) return NULL;

    t->x = x;
    t->y = y;
    return t;
}

int _test_mul(test_t t)
{
    return t->x * t->y;
}

Use a global variable holding the function pointers:

(This goes global):

typedef struct test *test_t;

struct {
    test_t (*create)(int const x, int const y);
    int (*mul)(test_t t);
} test = { // <- also implementation (you don`t want to expose private function names)
    .create = _test_create,
    .mul    = _test_mul
};

Then you would call it just like this:

test_t a = test.create(2, 6);

test.mul(a);

This has the advantage that you always see to what a is referenced to. But it also consumes more memory because of the test pointer table.

Other way around this (warning macro ahead):

#define test(obj, method, args...)    \
   (obj)->method(args)

test_t a = newTest(2, 6);
test(a, mul);

But this only works with pointers. And you need to be very careful.

Upvotes: 1

Greg Hewgill
Greg Hewgill

Reputation: 994011

One way is to define a helper function (named after the class name mult and the method name mul):

int mult_mul(mult *x) { return x->mul(x); }

Then you would:

mult a = newTest(2,6);
mult_mul(&a));

This provides the polymorphic behaviour without having to repeat the object name a. Of course for other methods you can add additional arguments to the mult_xxx() function.

Upvotes: 1

downhillFromHere
downhillFromHere

Reputation: 1977

I normally go for a macro, for instance

#define MUL(a) (a).mul(&(a))

Upvotes: 0

Related Questions