Reputation: 1461
I'm trying to learn c using learncodethehardway c book. In ex19 I have the following code:
int Monster_init(void *self)
{
Monster *monster = self;
monster->hit_points = 10;
return 1;
}
int Monster_attack(void *self, int damage)
{
Monster *monster = self;
printf("You attack %s!\n", monster->proto.description);
monster->hit_points -= damage;
if(monster->hit_points > 0) {
printf("It is still alive.\n");
return 0;
} else {
printf("It is dead.\n");
return 1;
}
}
Object MonsterProto = {
.init = Monster_init,
.attack = Monster_attack
};
This is the Object structure:
typedef struct {
char *description;
int (*init)(void *self);
void (*describe)(void *self);
void (*destroy)(void *self);
void *(*move)(void *self, Direction direction);
int (*attack)(void *self, int damage);
} Object;
And this is the Monster structure:
struct Monster {
Object proto;
int hit_points;
};
I'm having a tough time wrapping my head around the Monster_init
and Monster_attack
functions. I have a MonsterProto
variable of type Object defined and inside there .init
is set to the Monster_init
function and .attack
is set to the Monster_attack
function.
I think I understand the notion of void
in terms of declaring a function that has side effects but doesn't need to return something. What I don't understand is what exactly is the void *self pointer pointing at and why does it allow me to call a function with no arguments? What is the purpose of the self pointer?
I didn't want to include too much code here but if this is not enough context to answer the question, then you can find all the code here.
I appreciate any pointers in the right direction; nu pun intended :)
Upvotes: 1
Views: 160
Reputation: 25926
This code seems to be effectively implementing a kind of object-oriented approach.
self
is the address of the struct Monster
that you pass to those functions. Each of those functions operates on an individual object, and passing in the pointer to that object is how they know which one to work on.
This:
.init = Monster_init,
is not "calling a function with no arguments" - the init
member of your struct
is a pointer to a function returning an int
and accepting a single void *
parameter, and that line assigns the address of Monster_init()
to it. This way, if you have a pointer to an object, you can call int n = myobject->proto.init(&myobject);
or similar without knowing which actual function gets called. With a different object, you might be calling a different function with the same line of code.
Upvotes: 1