Skip to main content
Email Password   helpLost your password?

Simply Object-Oriented C

Source code and samples

Download ooc - 20 KB

Overview

This document describes a method by which features of Object-Oriented Programming (OOP) can be used in straight C, including Standard/ANSI C, and some variants of pre-ANSI C. The following compilers have been tested:

OOP constructs are implanted via C macros so that source code is easily readable. Knowledge of OOP is assumed as well as rudimentary knowledge of C++.

Background

This can serve both as an academic exercise for the reader that wants to see how object-oriented features can be built by-hand into a non-object-oriented language. It can also have a practical purpose in scenarios where the a C compiler needs to be used as as an intermediate step of a domain-specific language, or when the target device has limited compiler support.

Defining a class

To use this framework, each file should include the SOOC.h file

Every class in the SOOC system is derived from another class. If a class does not require a base class, the special class called Object is used as the base class. The definition of each class file is defined in a separate header file.

Since the best way to learn is by example, one is shown here.

In this example, the class Animal, is derived from Object. The class contains one data member, a 31 character string called �m_species�, two virtual methods called Talk and IsDomesticated, and two non-virtual methods called Report and SaySpecies.

Here�s side-by-side comparison of the class definition in C++ and in SOOC.

C++SOOC
//************************************
//  CLASS Animal
//************************************

class Animal
{

public:
    // Data members
    char m_species[32];  

    // Virtual methods
    virtual void Talk();
    virtual int IsDomesticated();
  
    // Non-virtual methods
    void Report();
    void SaySpecies();
};
  


/*******************************************************************/
#undef  CLASS
#define CLASS        Animal
#undef  BASECLASS
#define BASECLASS    Object
/*******************************************************************/

BEGIN_CLASS
 
       /* Data members */
       char m_species[32];
      
       /* Virtual methods */
       BEGIN_VIRTUAL_METHODS
              VIRTUAL_METHOD( Talk )
              VIRTUAL_METHOD( IsDomesticated )
       END_VIRTUAL_METHODS
      
       /* Non-virtual methods */
       BEGIN_NONVIRTUAL_METHODS
              NONVIRTUAL_METHOD( void, Report )( CLASS* this );
              NONVIRTUAL_METHOD( void, SaySpecies )( CLASS* this );
       END_NONVIRTUAL_METHODS
      
END_CLASS


Difference from C++:

The macros BEGIN_VIRTUAL_METHODS, END_VIRTUAL_METHODS, BEGIN_NONVIRTUAL_METHODS and END_NONVIRTUAL_METHODS pairs are required even if no virtual or non-virtual methods are specified.

Implementing a class

The implementation of each class file is defined in a separate source file. To continue with the above example, by implementing the class

C++SOOC
Animal::Animal()
{
       strcpy( this->m_species, "Animal" );
}
 
Animal::~Animal()
{}
 
void Animal::SaySpecies()
{
       �some implementation�
}
 
void Animal::Report()
{
       �some implementation�
}
 
void Animal::Talk()
{
       �some implementation�
}
 
int Animal::IsDomesticated()
{
       �some implementation�
}

 
 
 
 
 
 
 
 
 

 


BEGIN_CLASS_IMPLEMENTATION
 
       BEGIN_CONSTRUCTOR
       {
              strcpy( this->m_species, "Animal" );
       }
       END_CONSTRUCTOR
 
       BEGIN_DESTRUCTOR
       {}
       END_DESTRUCTOR
 
      
       BEGIN_NONVIRTUAL_METHOD( void, SaySpecies )( CLASS* this )
       {
              �some implementation�
       }
       END_NONVIRTUAL_METHOD
      
       BEGIN_NONVIRTUAL_METHOD( void, Report )( CLASS* this )
       {
              �some implementation�
       }
       END_NONVIRTUAL_METHOD
 
       BEGIN_VIRTUAL_METHOD( void, Talk )( CLASS* this )
       {
              �some implementation�
       }
       END_VIRTUAL_METHOD
 
       BEGIN_VIRTUAL_METHOD( int, IsDomesticated )( CLASS* this )
       {
              �some implementation�
       }
       END_VIRTUAL_METHOD
      
       BEGIN_OVERRIDES
              OVERRIDE( Animal, Talk )
              OVERRIDE( Animal, IsDomesticated )
       END_OVERRIDES

END_CLASS_IMPLEMENTATION


Difference from C++:

Note the BEGIN_OVERRIDES / END_OVERRIDES macros toward the end of the class. This lists the virtual methods that this class overrides. The macro OVERRIDE takes two parameters, the name of the class in which the method is defined, and the name method being overridden.

Inheriting from a class

Here a class named Who which will be derived from Animal. The top of the definition for the Who class looks like this:

/******************************************************************************/
#undef CLASS
#define CLASS Who
#undef BASECLASS
#define BASECLASS Animal
/******************************************************************************/

The Overrides section of the implementation file, looks like this:

BEGIN_OVERRIDES
OVERRIDE( Animal, IsDomesticated )
END_OVERRIDES

Note that this indicates that the method from the Animal class is being overridden.

Class Instantiation

As in C++, a class may be instantiated on the stack or the free-store (heap). Unlike in C++, the class constructor and destructor must be invoked manually. This is done using a special CONSTRUCT and DESTRUCT macro. The following is an example of instantiating the Animal class on the stack:

Animal animal;
CONSTRUCT( Animal, &animal );
�use the instance�
DESTRUCT( &animal );

The following is an example of instantiating a class on the free-store. This is done using the special NEW macro:

Cat* pCat = NEW( Cat );
CONSTRUCT( Cat, pCat );
�use the instance�
DELETE( pCat );

Note that, in the case where the class is instantiated dynamically, the DELETE macro, rather than the DESTRUCT macro, is used. The DELETE macro internally destructs the instance and the deletes the memory associated with it.

Data member access

The class Cat derives from Who. Its constructor sets the m_species data member of the Animal class. However, unlike in C++, the namespace of data-members aren�t automatically inherited. That is, if this were C++, from the body of a Cat method, one would be able to access the m_species data-member as if it were defined in the Cat class. However, in SOOC, the name of the class in which the data member is defined must be specifically referenced. Example:


BEGIN_CONSTRUCTOR
{
strcpy( ((Animal*)this)->m_species, "Cat" );
}
END_CONSTRUCTOR

Because m_species is defined in the Animal class, the Cat class instance specified by the this variable is cast to the Animal class first.

Method access

Methods are invoked using the CALL and VCALL macros, depending whether the method is non-virtual or virtual. The following is an example of calling the GetName method on the pCat instance where GetName is a method defined in the base class Who:

CALL( Who, GetName )( (Who*)pCat, name );

The VCALL macros requires a few more parameters. In this example, the VCALL macro is used to call Talk method of the pCat instance. Recall that the Talk method was defined in the Animal class and it returns void. This information must be supplied when making the method call because prototype for virtual methods are not specified in the definition of the method. The call looks like this:

VCALL( RVOID, Animal, Talk, pCat )( pCat );

The parameters to VCALL are as follows:

1. The return type of the method. RVOID, RLONG, etc.
2. The class in which the virtual method is defined.
3. The method to be called.
4. The instance being operated on.

The second set of parenthesis, in this case ( pCat ), indicate the parameters to the function. In this case, only the this pointer is passed.

Usage Set-up

Before the classes can be used, one source file, typically the one that defines the main function, will include the list of classes within special declaration macros BEGIN_DECLARE_APPLICATION_CLASSES and END_DECLARE_APPLICATION_CLASSES. Example:

BEGIN_DECLARE_APPLICATION_CLASSES
DECLARE_APPLICATION_CLASS( Animal )
DECLARE_APPLICATION_CLASS( Who )
DECLARE_APPLICATION_CLASS( Human )
DECLARE_APPLICATION_CLASS( Dog )
DECLARE_APPLICATION_CLASS( ShihTzu )
DECLARE_APPLICATION_CLASS( Beagle )
DECLARE_APPLICATION_CLASS( Cat )
DECLARE_APPLICATION_CLASS( Giraffe )
DECLARE_APPLICATION_CLASS( Cow )
END_DECLARE_APPLICATION_CLASSES

The class must be listed in derivation order.

Conclusion

This concludes the description of the SOOC library. See the included sample code for more information on how classes are instantiated, used, defined and implemented.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralObject-Oriented CPP Pin
The Wizard of Doze
1:29 10 Feb '08  
GeneralRe: Object-Oriented CPP Pin
Kenneth Kasajian
7:21 10 Feb '08  
GeneralA good exercise Pin
Shawn Poulson
3:08 17 Dec '07  
GeneralRe: A good exercise Pin
Kenneth Kasajian
21:29 17 Dec '07  
GeneralRe: A good exercise Pin
Shawn Poulson
2:28 18 Dec '07  
GeneralRe: A good exercise Pin
Kenneth Kasajian
13:25 19 Dec '07  


Last Updated 15 Dec 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009