Search code examples
cclass

Creating classes in C


is this how you guys would create a "class" in C? How about an interface? I'm guessing we just use function pointers for everything and we can change where the function pointers point to?

#ifndef CLASS
#define CLASS

void method1() { printf("method #1"); }
void method2() { printf("method #2"); }

typedef struct {
    void (*method1)(void);
    void (*method2)(void);
} Class;

Class class;

void class_setup()
{
    class.method1 = &method1;
    class.method2 = &method2;
}

#endif

int main()
{
    class_setup();

    class.method1();
    class.method2();

    return 0;
}

Solution

  • Actually, there are two ways to do OOP in C. And while function pointers do play a huge role in them, we do not put them inside the "class" structures that much - primarily because we do not have this in C.

    class as a set of functions in the open

    It is a most common and, while not exactly pretty, still usable approach. Just have a bunch of functions to do something with an object. For example, please take a look at Glib and GTK+. These two libraries are de-facto the most used and usable object oriented libraries in C. In case of GTK+, to work with "sibling" classes you use "sibling" functions:

    void gtk_window_set_child (GtkWindow* window, GtkWidget* child);
    void gtk_button_set_child (GtkButton* button, GtkWidget* child);
    

    As you can see, you need to pass a pointer to object (this) as a first parameter and distinction to which class this method belongs to is done by function names. At the same time, both classes (GtkWindow and GtkButton) are children of GtkWidget and can be passed directly to gtk_widget_*() functions with a manual type conversion:

    GtkButton *button = gtk_button_new();
    gtk_widget_set_size_request((GtkWidget*)button, 100, 100);
    

    Actually, early C++ compilers were just preprocessors which made a C code using same approach. A method cls::foo() becomes a function cls_foo(cls *this). And even now, if you compile C++ code into a shared library, you will see inside just a bunch of functions with names like this. Read about "name mangling" and how it is done by different compilers.

    class as a set of functions in a hidden hash table

    This approach to do OOP, is much less used. In commercial product it was implemented in Photon - GUI library for old QNX (newer version of OS switched to C++ for GUI). As example of open source project: IUP

    It uses a different approach to methods - a hash array of function pointers. When you creating a new class, you need to register its unique type in the list of classes and register all methods. Also there is no parent-child data types, only a base data type with a class identifier inside an object. Not very easy inside, but this allows a more convenient way for practical application:

    PtWidget_t *window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 0, NULL);
    PtArg_t const btn_args[] = {...};
    PtWidget_t *button = PtCreateWidget( PtButton, window, btn_arg_cnt, btn_args);
    // Here PtWindow and PtButton are references to registered classes
    
    // and both widgets can be passed to a single function
    PtSetResource (window, Pt_ARG_TEXT_STRING, "Window title", 0);
    PtSetResource (button, Pt_ARG_TEXT_STRING, "Click Me!", 0);
    

    And behind the scene the PtSetResource() function will use a two dimensional hash table of function pointers keyed on class references (PtWindow or PtButton read from inside an object) and on method selector (Pt_ARG_TEXT_STRING) passed directly to the function.