C89-OOP: Class
Today I'll try to explain as simple as possible what a basic class would look like in C89. so it's easier to understand later the choices I make for emulation of OOP. I make the assumption that we're emulating static OOP, not something crazy like prototypes.
In essence, a class
is nothing more than a struct
(fields) with functions (methods). In order to know which instance to manipulate the data from, a method contains a hidden pointer (this
keyword) which points to the instance. Type aliassing (typeof
) is used to give every class it's own type.
For example, let's take this class:
class Foo
{
int x;
Foo(int x)
{
this.x = x;
}
int getX()
{
return this.x;
}
}
We got the field x
, a constructor to initialize the value of x
and a method that returns the value of x
. Foo is an user-defined type.
Emulating this is not very hard in C89:
typedef struct Foo Foo;
struct Foo
{
int x;
};
void Foo_ctor(Foo* self, int x)
{
self->x = x;
}
int Foo_getX(Foo* self)
{
return self->x;
}
For those familliar with C, there isn't anything special here. Note that this
is renamed to self
to ensure compatability with C++ (which has a this
keyword in its language).
typedef struct Foo Foo;
Here we use type aliassing to make Foo
its own type.
struct Foo
{
int x;
};
This is where Foo
's fields and class information (more on this later) are stored, which is in our case only x
.
void Foo_ctor(Foo* self, int x)
{
self->x = x;
}
This is the constructor (ctor). Here we initialize the value of the member x
. We use the self
parameter to know which instance of Foo
to initialize.
int Foo_getX(Foo* self)
{
return self->x;
}
This is the user-defined method. Pretty much the same as above; self
contains the instance to operate on.
Conclusion
You've now learned what the antonomy of a class looks like, how to convert this to C89, and that the this
keyword needs a bit of special care for emulation.
In the next article I'll discuss how to do single inheritance!