W3C libwww C Style

C++ in C

C is much more widely supported than C++. There is a subset of C++ that is common to all C++ compilers but it can be emulated in C with minimal loss in efficiency or readability. This subset includes

While the C++ in C approach is not perfect, it does allow much greater portability.

Construction / Destruction

C++ provides language primitives for memory allocation (new) and freeing (free). These functions call the constructor and destructor for an object. The libwww implements this in C with object_new and object_delete. For example:

	PUBLIC HTRequest * HTRequest_new (void)
	{
	    HTRequest * me;
	    if ((me = (HTRequest *) HT_CALLOC(1, sizeof(HTRequest))) == NULL)
	        HT_OUTOFMEM("HTRequest_new()");
    
	   /* Force Reload */
	    me->reload = HT_ANY_VERSION;
	.
	.
	.
	    me->ContentNegotiation = NO;		       /* Do this by default */

	#ifdef WWW_WIN_ASYNC
	    HTEvent_winHandle(me);
	#endif
	    return me;
	}

Data Hiding

Many classes are defined in C++ to be private, meaning that all manipulation of the object is done through member functions (methods). Any attempt at meddling with the contents by an outside function will result in a compiler error. Object data is protected in libwww by declaring a structure in a header file, but not defining it. That is, the object is opaque to the application - exactly like the ANSI C FILE object.

	typedef struct _MyObject MyObject;

	int MyObject_saveTheWorld(MyObject * me);

The method (saveTheWorld) is accessible to everyone including the header, but the contents of a MyObject are not. Only the module containing MyObject's methods has a definition of the object,

	struct _MyObject {
	    int someInt;
	};

and therefore, access to the contents (someInt);

Name spaces

Most C++ objects come with a set of methods (member functions) which are permitted to affect the object. Any operation performed on an object (myObject->saveTheWorld) will be performed by an method in that object's class.

	class MyObject {
	private:         // data
	    int someInt;
	public:          // methods
	    int saveTheWorld(void);
	}
	main ()
	{
	  MyObject * myObject = new MyObject;
	  myObject->saveTheWorld();
	}

What is actually happening is that the compiler is generating a name from the class name and the method name, e.g.. _@MyObject@@saveTheWord@132. This is done explicitly in libwww, e.g. MyObject_saveTheWorld.While more verbose, this does, at least, eliminate the awkward hunt to figure out what instance of a method the compiler used.

"this" pointer

The this pointer is simply an understood first parameter to any method. libwww includes all parameters explicitly.

	C++:	myObject->saveTheWorld();

is equivalent to

	libwww:	MyObject_saveTheWorld(myObject);

Inheritance

In C++, classes may be derived from other classes.

	class MyOtherObject: public MyObject {
	private:         // data
	    int anotherInt;
	public:          // methods
	    int saveTheWales(void);
	};

As far as memory is concerned, this is identical to

	struct _MyOtherObject {
	    MyObject base;
	    int anotherInt;
	};

but one problem remains. In C++, all the instances of MyOtherObject may call myOtherObject->saveTheWales() as well as myOtherObject->saveTheWorld(). The compiler knows that a pointer to a MyOtherObject also points to a MyObject, so saveTheWorld may be called with the same pointer as saveTheWales. This is much trickier than the others as it requires more logic on the part of the compiler.

In libwww, this is mostly handled through explicit pointer casting.  As an example, an HTStream class always includes an HTStreamClass as the first element (normally called isa). This way, the local definition of the HTStream may vary from module to module, depending on what context is needed to process the stream, but the library can use the standard HTStreamClass functions to supply it with data.


Eric Prud'hommeaux, Henrik Frystyk Nielsen, libwww@w3.org
@(#) $Id: Cpp.html,v 1.4 1996/12/09 03:23:04 jigsaw Exp $