ANSI C and object-oriented programming

Do you think that to program in an object-oriented style you need an object-oriented language? Well, you're wrong. It seems to be a common myth that you need an object-oriented language to implement an object-oriented design and, although languages such as C++ and Java provide many features that encourage this style of design, you can benefit equally well from the use of objects in imperative languages such as C.

The Web-Server uses no global data. All data is presented as objects to the user. The object type is a C struct. Each object type has a number of member functions or methods associated with the object. Accessing the data in the objects is done via these member functions. You should never directly access the data in the C struct. The member functions starts with the same name as the type. For example, class HttpRequest has a member function getHeaderValue. The fully qualified C function name will therefore be HttpRequest_getHeaderValue and the C++ name will be HttpRequest::getHeaderValue.

All C member functions take a pointer to an instance of the type as the first argument. For example, the HttpRequest_getHeaderValue takes the HttpRequest* type as the first argument. You use the "this" pointer in C++, thus you do not explicitly pass in the pointer to the class itself.

C code: const char* HttpRequest_getHeaderValue(HttpRequest* o, const char* name); C++ code: const char* HttpRequest::getHeaderValue(const char* name);

We use the notation "o" as the "object pointer" in the C code, which is equivalent to the automatic "this" pointer in C++.

Some of the classes in Barracuda are abstract classes, which can be seen as a protocol between the Web-Server and the application code. You must inherit and implement the functionality of the abstract class before registering an instance of the class with the Web-Server. Such a class is HttpPage.

typedef struct { HttpPage super; /* As if inherited */ int myOwnVar; } MyPage;

The HttpPage object is actually an aggregate of the MyPage type. It is important that HttpPage is the first aggregate in the struct. For example, the following code will not work.

typedef struct { int myOwnVar; HttpPage super; /* Ooops */ } MyNonWorkingPage;

A C++ compilers will be memory compatible with the C code if you write:

C code: typedef struct { HttpPage super; /* As if inherited */ int myOwnVar; } MyPage; C++ code is memory compatible with above code: class MyPage : public HttpPage { int myOwnVar; };

In C++ a constructor is used to initialize an instance of a class. We use the notation "struct name" followed by the name "_constructor"; for example, the HttpPage C initialization function name is HttpPage_constructor and the C++ version is HttpPage::HttpPage. You must explisitly call the constructor as a function when writing C code. The following code example shows how to write a constructor for the MyPage class.

MyPage_constructor(MyPage * o) { /* It is safe to typecast MyPage to HttpPage since HttpPage is the first * aggregate in MyPage. We have to explisitly downcast MyPage to HttpPage * in C code. C++ would implisitly downcast the type. */ HttpPage_constructor((HttpPage*)o,MyPage_service, "MyPage"); }

The second argument, MyPage_service, is the page service function. In a pure C++ environment, one would typically use virtual functions for overloading the behavior in the super class, but virtual functions cannot be used by C code, thus C function pointers must be used in both C and C++ code.

Other classes such as the HttpDir class can be used as is, or can be overloaded, that is, the functionality of the HttpDir class can be extended or customized. Using function pointers does this and one can replace the default service function in the HttpDir with a customized service function.

Back to White Paper