{"id":26728916,"url":"https://github.com/slashdotted/oo-in-c","last_synced_at":"2025-04-14T09:20:17.274Z","repository":{"id":157956082,"uuid":"112583525","full_name":"slashdotted/oo-in-c","owner":"slashdotted","description":"OO in C (in 100 lines of code)","archived":false,"fork":false,"pushed_at":"2017-11-30T08:12:39.000Z","size":8,"stargazers_count":5,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T22:40:24.379Z","etag":null,"topics":["100-loc","bsd","c","interface","library","object-oriented","object-oriented-programming","oop","programming"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slashdotted.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-30T08:07:58.000Z","updated_at":"2024-05-17T06:41:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"fa587a1b-6f73-4527-b204-f42746a97006","html_url":"https://github.com/slashdotted/oo-in-c","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdotted%2Foo-in-c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdotted%2Foo-in-c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdotted%2Foo-in-c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdotted%2Foo-in-c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slashdotted","download_url":"https://codeload.github.com/slashdotted/oo-in-c/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852186,"owners_count":21171843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["100-loc","bsd","c","interface","library","object-oriented","object-oriented-programming","oop","programming"],"created_at":"2025-03-27T22:37:21.564Z","updated_at":"2025-04-14T09:20:17.256Z","avatar_url":"https://github.com/slashdotted.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OO in C (in 100 lines of code)\n\nWelcome! This library provides simple OO (Object-Orientation) to the C language, all in just 100 lines (which refers to the size of *object.h* and *object.c*, a.k.a the core of this small library, ignoring comments).\n\n## Creating a new class\n\nCreate a *myclass.h* file. This will will define the required data structures and provide public function prototypes for your class:\n```C\n#ifndef MYCLASS_H\n#define MYCLASS_H\n\n#include \"object.h\"\n```\nThe first structure we need for our class is the *instance structure*, which will be used for each instance (object) of our class. The instance structure embeds the structure of the base class (in our case we are deriving from the root class, which is *Object*). The parent instance structure MUST BE the first member of the struct. We can define additional members which will act as instance variables:\n```C\n// Instance structure\ntypedef struct {\n    Object parent; // Parent instance structure\n    // instance members \n} MyClass;\n```\nThe second structure is the *class structure*, which is shared by all instances. The class structure also embeds the parent class structure (in this case *ObjectClass*). Additional members for this structure are function pointers (for polymorphic methods) and pointers to static class members:\n```C\n// Class structure\ntypedef struct {\n\tObjectClass parent; // Parent class structure\n\t// Polymorphic methods (function pointers)\n\t// Static members (MUST BE declared as pointers in order to be shared across all class hierarchies)\n} MyClassClass;\n```\nFinally we need to define prototypes for some basic functions and some convenience macros:\n```C\nMyClassClass* myclass_get_class();\n\n#define MYCLASS_TYPE myclass_get_class()\n#define IS_MYCLASS(obj) instance_of(AS_OBJECT(obj), MYCLASS_TYPE)\n#define AS_MYCLASS(obj) (IS_MYCLASS(obj) ? (MyClass*) obj : NULL)\n#define AS_MYCLASS_TYPE(type) ((MyClassClass*) type)\n\nvoid myclass_init(MyClass* ref); // Constructor\n\n#endif\n```\nThe constructor for our class initializes a *MyClass* instance structure and can take any additional parameter.\nThe implementation for our class goes into *myclass.c*:\n```C\n#include \u003cstdlib.h\u003e\n#include \"myclass.h\"\n\nvoid\nmyclass_init(MyClass* ref)\n{\n    object_init(\u0026ref-\u003eparent); // Initialize the parent object\n    SET_INSTANCE_TYPE(ref, MYCLASS_TYPE); // Set the type of the object\n    // MUST BE called AFTER the parent object\n    // constructor, in order to overwrite\n    // the parent type\n\n    // Initialize instance members\n}\n```\nThe constructor MUST first call the parent object constructor (in this case *object_init*), subsequently it MUST set the instance type using the *SET_INSTANCE_TYPE* macro: the first parameter is the pointer to the instance structure (*ref*) and the second parameter is the type (obtained using the *MYCLASS_TYPE* macro).\nThe latter is bound to the *myclass_get_class* function which is defined as follows:\n```C\nMyClassClass*\nmyclass_get_class()\n{\n    static MyClassClass* class_structure = NULL;\n    if (!class_structure) {\n        class_structure = (MyClassClass*) malloc(sizeof(MyClassClass));\n        EXTENDS(class_structure, OBJECT_TYPE)\n        // Override methods, declare static fields\n    }\n    return class_structure;\n}\n```\n\nThis function creates and returns a singleton instance of a *MyClassClass* structure (the *class structure*), which is used both for accessing class related stuff (such as polymorphic methods and static members) and as type identifier. After allocating memory for the class structure we NEED TO declare that our class is derived from the *Object* class using the *EXTENDS* macro: the first parameter is a pointer to the class structure, wherease the second parameter is the parent class type (*OBJECT_TYPE*). After the *EXTENDS* macro we can put additional code to override methods or declare static fields.\n\n## Using our class\n\nTo use *MyClass* simply declare a variable of type *MyClass* and call the *constructor*:\n```C\nMyClass myobject;\nmyclass_init(\u0026myobject);\n```\n\n## Declaring new public members and (non-polymorphic) methods\n\nPublic members are declared within the instance structure, for example:\n\n```C\n// Instance structure\ntypedef struct {\n    Object parent; // Parent instance structure\n    // instance members\n    int value;\n} MyClass;\n```\nInitialization takes place in the constructor, which can be modified in order to accept an additional parameter used to set *value*:\n\n```C\nvoid\nmyclass_init(MyClass* ref, int value)\n{\n    (...)\n    // Initialize instance members\n    ref-\u003evalue = value;\n}\n```\nWe can also define two methods for getting and setting the value:\n```C\n// in myclass.h\nint myclass_get_value(MyClass* ref);\nvoid myclass_set_value(MyClass* ref, int value);\n\n// in myclass.c\nint\nmyclass_get_value(MyClass* ref)\n{\n\treturn ref-\u003evalue;\n}\n\nvoid\nmyclass_set_value(MyClass* ref, int value)\n{\n\tref-\u003evalue = value;\n}\n```\nThose methods are not polymorphic, which means that they cannot be overridden in a derived class. Nonetheless, we can test that our code works correctly by changing the value in the example code:\n```C\nprintf(\"value is %d\\n\", myclass_get_value(\u0026myobject));\nmyclass_set_value(\u0026myobject, 33);\nprintf(\"value is %d\\n\", myclass_get_value(\u0026myobject));\n```\n\n## Going further\n\nIn *derived.h* and *derived.c* you find an example of a class which extends *Object* and shows you how to implement *private* members and how to implement/override *polymorphic* methods. Moreover, *doublederived.h*, *doublederived.c*, *idrawable.h* and *idrawable.c* provide an example on how to extend *Derived* and declare/implement and interface. Finally, in *main.c* you will find an example of usage of all these classes (and of some convenience macro).\n\n## License\n\nThe code of the library (found in *object.h* and *object.c*) is released under a BSD 3-clause license (see *LICENSE* for details). Examples (derived.c, derived.h, doublederived.c, doublederived.h, idrawable.c, idrawable.h, main.c) are public domain.\n\n## Comments? Questions? Bugs?\n\nIf you have any comment, question or if you found a bug in the code please don't hesitate to contact me at amos _DOT_GOES_HERE_ brocco _AT_GOES_HERE_ supsi _DOT_GOES_HERE_ ch . Thank you!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslashdotted%2Foo-in-c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslashdotted%2Foo-in-c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslashdotted%2Foo-in-c/lists"}