OBC Objects

An OBC object is a C object that understand virtual OBC methods. When we have different objects, it would be convenient if we could print and destroy our cars, boats and other objects, without knowing their specific type. This is called polymorphism and a key feature of every object oriented language. So what we would like to write in the main function is something like:

main.c

    #include "../obc/objI.h"
    #include "car.h"
    #include "boat.h"
    
    int main(){
        Obj    vehicles[3];
        int    i;
    
        /* create objects */
        vehicles[0] = car_create();
        vehicles[1] = car_create();
        vehicles[2] = boat_create();
    
        /* use objects */
        for(i=0; i < 3; i++) {
            obj_print(vehicles[i], stdout);
        }
    
        /* free objects */
        for(i=0; i < 3; i++) {
            obj_destroy(vehicles[i]);
        }
    
        return 0;
    }
  

To build this you must compile and link obj.c, objI.c, car.c, boat.c, main.c . Also note that main.c now includes objI.h When you let it run you will get an error message that some object doesn't understand the message print. Although car has a print message implemented, OBC doesn't know that you are referring to this print message. So lets tell it by including objI.h in car.c and boat.c and change the constructors. We use the macro REGISTER() to register our methods to the car object.

car.c

    #include "../obc/objI.h"
    
    ...
    
    void car_destroy(Car self) {
        testCar(self);
        obj_destroyInfo(self);
        free(self); 
    }
    
    Car car_create() {
        Car self = (Car)malloc(sizeof(CarImpl));
        REGISTER(self, obj_print,   car_print);
        REGISTER(self, obj_destroy, car_destroy);
        self->speed = 0.0f;
        return self;
    }
  

boat.c

    #include "../obc/objI.h"
    
    ...
    
    void boat_destroy(Boat self) {
        testBoat(self);
        obj_destroyInfo(self);
        free(self); 
    }
    
    Boat boat_create() {
        Boat self = (Boat)malloc(sizeof(BoatImpl));
        REGISTER(self, obj_print,   boat_print);
        REGISTER(self, obj_destroy, boat_destroy);
        self->speed = 0.0f;
        return self;
    }
  

If you run it again, it will output the speed 0 for 3 vehicles. Messages can be registered with REGISTER(object, method, implementation). Do not forget to free the OBC resources in the destructor with obj_destroyInfo(). This is very important. Because if your reallocate this memory block it might still know some wrong messages. The virtual messages defined in the object interface (objI.h) are:


Some important messages defined in obj.h are:


At the forward messages will we look when we gonna talk about inheritance. With obj_understands() can you test if an object will understand a message. obj_config() gives the object a type name. This is useful for debugging. If you get a message not understood error, this type name is printed together with the object address. Also obj_isa() does only work, when a type name is configured. obj_printInfo() prints a list of messages that the object understands.