Doing C OOP Style: Structure members as Class Attributes

In this post, we are going to discuss a classy technique to assign values to members of a structure in C programming language as if they were some members of a class in some OOP language.

You might be knowing that C language does not natively support Object Oriented Programming constructs and that if you are to do programming in an object oriented fashion, you need specialized languages like C++, Python, PHP or Java as the immediate recourse. But, knowing that C++ and Python have been written in C, it cannot be possible that C metamorphosizes into something entirely different when it transitions into C++ or any other High Level Language. If we can do OOP in C++, then there must be some way to do it in C too, though with a lot more effort. Now, I am not a OOPs specialist, infact I don't understand it very well in implementation due to lack of exposure. I code in C for a living, but somewhere between coding in C and making the code more scalable and modular, I've rediscovered the need to have something we now call Objects. I'd tell you the story some other day, today, I just wish to demonstrate how a very close parallel of Object Classes can be developed inside C knowing what we already know and perhaps, a little bit new information. Now remember, it isn't the final form of class that you might be expecting. C does not support classes natively, (but it can be made to do so through hard, incremental work if the cause is justified). What we're doing here is the beginning of it, were're starting to model things what an Object Oriented perspective.

The closest parallel to a class from OOP in C is a structure. It is like, classes are structures, with a lot of bling. While I'll keep the discussion of a more complex class for some other post, I'll show you three methods in which a structure and its members may be declared. You might be aware of two of them, but the third one is more cool (actually it strikes a middle ground between two methods). Without further ado, lets do it with an example.

Book as Struct

Consider the example of representing books as our black box unit of representation. A book has various attributes, or properties which help us identify it without having to look inside, the most generic being:

  • Title of Book
  • Author(s)
  • ISBN
  • Genre
  • Publisher
  • Price
  • Edition

For the present discussion let us assume there is just one author. First, we represent it as a structure in C.

typedef struct book_type {
    unsigned char title[255]; 
    unsigned char author[255]; 
    unsigned long isbn; 
    unsigned char genre[255];
    unsigned char publisher[255]; 
    unsigned int price_inr; 
    unsigned short edition; 
} BOOK;

Right now, we've just described how a structure will look like, i.e. it is a structure definition. We've typedef-ed it to save our hands from typing the excruciatingly long 'struct book' by merely writing 'BOOK'; Not that it makes a difference here, but the names tend to get long as the complexity of the entire project increases and coding etiquette or guidelines come into force. So, now we can start filling in the data using different methods. Lets start with the 'here and now' kind of method.

BOOK book = {
    "The C Programming Language", 
    "Dennis Ritchie", 
    0131103628, 
    "Technical", 
    "Prentice Hall", 
    146, 
    2 };

Here, we are telling everything in sequence and in one place. Short and sweet, but we need to keep in mind the exact order of the members and the data type of that member. This is called the C89-style initializers style. But that short and sweet is a bitter pill when the number of structures is large, and so are the number of members in it. Also, data types aren't the only things that go into a structure. Even functions can (and that, gentlemen and ladies, is how we'll make a class). So, we'd like a more flexible style. Yep, we have that too; here:

BOOK book;
book.title = "The C Programming Language";
book.author = "Dennis Ritchie";
book.isbn =  0131103628;
book.genre = "Technical";
book.publisher = "Prentice Hall";
book.price_inr = 146;
book.edition = 2;

Much better? I don't know if it also has a technical name. But did you see how much did we had to type? Compare it with the previous method. So much for flexibility! But then, there is a third method which is the essential take away from this post. Lets see it first and then discuss it later.

BOOK book = {
    .title = "The C Programming Language" ,
    .author = "Dennis Ritchie" ,
    .isbn = 0131103628 ,
    .genre = "Technical",
    .publisher = "Prentice Hall" ,
    .price_inr = 146,
    .edition = 2
    };

This is the middle ground between the previous two approaches. We don't need to enter anything in a particular order, and at the same time don't need to write book.xxx prefix to each attribute of the structure. This is more compact when we already know what to assign to each member. This also comes in handy when we are trying to write pointers to functions which can be thought of as methods of a class.

Why do I compare this declaration with OOPs, because when we initialize an object, we populate all of its members and methods (in case of an interface), encapsulation being the key driver for such approach here. By extending this structure using unions or structures whose members are structures, we can implement class inheritance and by having pointer to functions, we can have some degree of encapsulation too. But we'll keep that discussion for some other day.

(Image Credits: Google)