Being able to print and destroy different objects is very nice, but how can we accelerate cars and boats, without knowing their type? We must define our own vehicle interface. In OBC, an interface is simply a collection of virtual messages, that somehow belong together. To define this interfaces, we need some magic macros that are defined in obj.h . Interfaces, like objects, need a header and a c file. So here is a vehicle interface, that defines the functions:
vehicleI.h
#ifndef VEHICLE_H_
#define VEHICLE_H_
#include "../obc/obj.h"
DEFINE_METHOD( vehicle_accelerate)
DEFINE_METHOD1( vehicle_setLicenceNumber, const char*)
DEFINE_FUNCTION(float, vehicle_getSpeed)
#endif /*VEHICLE_H_*/
vehicleI.c
#include "vehicleI.h"
DEFINE_METHOD_BODY( vehicle_accelerate)
DEFINE_METHOD1_BODY( vehicle_setLicenceNumber, const char*)
DEFINE_FUNCTION_BODY(float, vehicle_getSpeed)
A void function is defined with DEFINE_METHOD(name) and DEFINE_METHOD_BODY(name).
A function with a return value is defined with DEFINE_FUNCTION(returnType, name)
and DEFINE_FUNCTION_BODY(returnType, name). And if the method or function
takes more parameter than just the self pointer? Since Ansi C89 macros can
not take arbitrary arguments we must tell the macros how many arguments are
required. Therefore you must add the number of parameters, that the function
requires to the macro name. For example to define a virtual function for
const char* obj_getString(Obj, int, float, double); write:
xxx.h: DEFINE_FUNCTION3(const char*, obj_getString, int, float, double)
xxx.c: DEFINE_FUNCTION3_BODY(const char*, obj_getString, int, float, double)
The limit for additional parameters is 6. Of course not because I was to lazy
to write more macros but to keep your function signatures understandable ;-).
Now we can rewrite our main function to use the accelerate method from the
vehicle interface:
main.c
...
#include "vehicleI.h"
int main(){
...
/* use objects */
for(i=0; i < 3; i++) {
vehicle_accelerate(vehicles[i]);
obj_print(vehicles[i], stdout);
}
...
}
As expected, if we run this we get a unknown message error because cars and boats still have no clue how to accelerate. Here is how we fix this in the constructors:
car.c
...
#include "vehicleI.h"
...
Car car_create() {
Car self = HEAP_ALLOC(CarImpl, 1);
REGISTER(self, obj_print, car_print);
REGISTER(self, obj_destroy, car_destroy);
REGISTER(self, vehicle_accelerate, car_accelerate);
REGISTER(self, vehicle_getSpeed, car_getSpeed);
self->speed = 0.0f;
return self;
}
boat.c
...
#include "vehicleI.h"
...
Boat boat_create() {
Boat self = HEAP_ALLOC(BoatImpl, 1);
REGISTER(self, obj_print, boat_print);
REGISTER(self, obj_destroy, boat_destroy);
REGISTER(self, vehicle_accelerate, boat_accelerate);
REGISTER(self, vehicle_getSpeed, boat_getSpeed);
self->speed = 0.0f;
return self;
}
While we were at it, we also registered the speed getter method. If you compile, link and run obj.c, objI.c, car.c, boat.c, vehicle.c, main.c you should get an output like:
Car speeds at 100 km/h
Car speeds at 100 km/h
Boat speeds at 10 km/h
This is how you do object based programming with OBC. If you know Java or C++ you probably have one more burning question. How do I use inheritance?.