Developing Yed objects - The constructor
The aim of constructor is the right initialization of an
object. In Yed scenario, this axiom becomes fundamental: we
can't create static object, because the C compiler, unlike
C++, does not produce automatically the needed code. But we
can create a dynamic object through a function, release this object through
another function, and code into these functions all we need in order to create
an instance of the object right for us.
These functions are the constructor and the destructor
of Yed objects. Their interface and implementation is particular,
so let's start to examine the characteristics of Yed objects
constructors.
A constructor must have the name equal to the name of object it refers to, with the first character equal to '_' ( underscore ); we will see later the reason why. Moreover, it must return a valid pointer to an instance of the object.
In our example, the constructor's interface and first implementation are in red:
#include "yedstd.h"
#include "myclass.h"
MyClass * _MyClass(void) {
........
}
int My_Func(void *pVWork) {
MyClass *this=pvWork; //
'THIS' POINTER OF THE INSTANCE!!!
printf("The protected member value is [%d]\n", this->PRIVATE(protected));
return 0;
}
What about the implementation of the constructor ?
An object can have any number of attributes: they can be publics or privates,
and they can be initialized before use to a default values. Moreover, an object
can have any number of methods; we have written a method ( see ' Writing
methods ' paragraph ), but we don't have linked its implementation with
an interface, then we can't invoke this method yet. The constructor implements
all these features and returns to the external environment a pointer to an object
ready to use and correctly initialized.
Let's see how.
Do you remember interface of MyClass object?
typedef struct{
PUBLIC char my_attr;
PUBLIC int (*My_Func)(void *);
char PRIVATE(protected);
} Myclass;
The implementation of the constructor of MyClass object could be:
#include "yedstd.h"
#include "myclass.h"
1 MyClass * _MyClass(void) {
2 MyClass *this=malloc(sizeof(MyClass));
3 if(this!=NULL) {
4 memset(this,0,sizeof(MyClass));
5 this->My_Func=My_Func;
6 this->PRIVATE(protected)=24;
7 }
8 return this;
9 }
int My_Func(void *pVWork) {
MyClass *this=pvWork; //
'THIS' POINTER OF THE INSTANCE!!!
printf("The protected member value is [%d]\n", this->PRIVATE(protected));
return 0;
}
We have temporarily put line numbers in constructor for clearness.
Line 1 is the interface definition of the constructor.
Line 2 contains the dynamic allocation of memory for the object. Through the explicit invocation of the constructor, we create an instance picking up in the heap as memory as we need.
Line 4 resets the allocated buffer.
Line 5 shows the way to initialize methods in Yed scenario. The My_Func pointer to function in MyClass object interface is linked to the implementation of the method, called My_Func, coded below. In this way, invoking the content to the pointer My_Func, we invoke the function My_Func. Every method in an object must be linked to its implementation in this way.
Line 6 initializes the private attribute called protected at the value 24.
Line 8 returns a pointer to MyClass object ready to use, or NULL if there is not enough memory in the heap.
The constructor is complete. But it's possible to generalize the invocation of every Yed constructor using an appropriate interface and a macro defined in the header file yedstd.h. Let's see how:
/*************************************************
NOME : YEDSTD.H
*************************************************/
#ifndef YEDSTD
#define YEDSTD
/****************
MACRO DEFINITION
****************/
#define PUBLIC
#define PRIVATE(x) __P##x
#define PRIVATE_FUNCTION static
/**** DYNAMIC CONSTRUCTOR AND DESTRUCTOR ****/
#define New(x) (x *)_##x()
#define Delete(x,a) _D##x(a)
/****************/
#endif
Look at the red line: this macro generalize invocation of
Yed object constructors, as long as they have properly interface.
How ?
C preprocessor substitutes every string 'New(x)'
with the string '(x*)_##x()'. The
token '##' means concatenation
of string in preprocessing of C source code.
So, if we write:
MyClass *myp=New(MyClass);
the output of C preprocessor will be:
MyClass *myp=(MyClass *)_MyClass();
that is, the invocation of the constructor. This is the reason
why the name of Yed constructors has underscore character before
object name.
Through the macro 'New(x)', we
can use the same invocation for every Yed constructor. But
it's very important that the constructor has the properly interface, else we
must explicitly call the constructor in object definition without using the
macro.
The application using MyClass object becomes now:
#include "yedstd.h"
#include "myclass.h"
main(){
MyClass *myClassInstance;
myClassInstance=New(MyClass);
if(myClassInstance!=NULL) {
myClassInstance->My_Func(myClassInstance);
}
.....
}