Encapsulating instance structure

1

Given the following code, implement a small library that makes it possible.

#include <stdio.h>
#include "object.h"

int main() {
    obj_instance *oi1;
    obj_instance *oi2;
    
    object_init();
    
    oi1 = Object.New();
    oi2 = Object.New();

    Object.Set(oi1, 5);
    Object.Set(oi2, 3);
    
    printf("valor de oi1: %d\n", Object.Get(oi1));
    printf("valor de oi2: %d\n", Object.Get(oi2));

    printf("oi1 y oi2 ");
    if(!Object.Equals(oi1, oi2))
        printf("NO ");
    printf("son iguales.\n");

    Object.Set(oi2, 5);
    
    printf("valor de oi1: %d\n", Object.Get(oi1));
    printf("valor de oi2: %d\n", Object.Get(oi2));
    
    printf("oi1 y oi2 ");
    if(!Object.Equals(oi1, oi2))
        printf("NO ");
    printf("son iguales.\n");
   
    Object.Free(oi1);
    puts("oi1 liberado.");
    
    Object.Free(oi2);
    puts("oi2 liberado.");
}

You can not allocate memory using obj_instance as an argument to malloc . That is, this code should fail:

obj_instance *un_objeto = malloc(sizeof(obj_instance));

Object is an instance of obj_instance ? How can I encapsulate obj_instance ?

    
asked by anonymous 09.01.2017 / 16:51

1 answer

3

I do not know if this is what you need exactly, but to achieve the purpose you ask, I would do the following:

File "object.h" :

typedef struct obj_instance obj_instance;

typedef struct Object_vtable {
    void (*Set)(obj_instance *, int);
    int (*Get)(obj_instance *);
    int (*Equals)(obj_instance *, obj_instance *);
    obj_instance *(*New)();
    void (*Free)();
} Object_vtable;

extern Object_vtable Object;

void object_init();

File "object.c" :

import "object.h"

typedef struct obj_instance {
    int value;
} obj_instance;

Object_vtable Object;

void Set(obj_instance *instance, int value) {
    instance->value = value;
}

int Get(obj_instance *instance) {
    return instance->value;
}

int Equals(obj_instance *a, obj_instance *b) {
    return a->value == b->value;
}

obj_instance *New() {
    obj_instance *instance = (obj_instance *) malloc(sizeof(obj_instance));
    instance->value = 0;
    return instance;
}

void Free(obj_instance *instance) {
    free(instance);
}

void object_init() {
    Object.New = New;
    Object.Free = Free;
    Object.Equals = Equals;
    Object.Get = Get;
    Object.Set = Set;
}

The idea here is to use a vtable , basically a structure that contains multiple pointers to functions. This is analogous to a class and each of these function pointers is analogous to a method.

The Object structure is of type Object_vtable , and there are only one of these statically declared. It serves as the definition of a class.

malloc exists within object.c . But the attempt to do this in main.c will go awry because the object.h header only contains typedef struct obj_instance obj_instance . Attempting to access the value attribute directly on main.c will also give compile error (it is private). Thus, when parsing main.c , the compiler will know that there is a structure called obj_instance , but it will not know the content of it, and therefore will not know its size, so sizeof of malloc will fail. This information will only be available to the compiler within object.c and will only appear to the program as a whole in the linking step.

This is still quite primitive in turning C into an object-oriented language. There is still no concept of subclasses, neither polymorphism nor interfaces, although you already have something that will become a constructor, a destructor and some methods. It is also possible to have an idea how to implement the concept of public and private, since in this resulting code, the value attribute is private and the methods are public. Methods of type is_instance and get_class will also be useful later, as well as making the structures that represent classes are themselves objects themselves. That's all, you'll implement later.

    
09.01.2017 / 18:38