Introduction
This article describes a simple way to design object oriented programming concepts in traditional C language.
The description is as follows:
1. Please refer the code below for better understanding of the description. The code given at the end is actually a working code and there should not be any compilation and execution issues.
2. struct A is equivalent to a 'class' like in any Object Oriented programming language.
3. Various member of A; like a, b, c; are data members of the class
4. Various members of A; like add, sub and print; are member function of the class. Basically they are pointers to functions and would be initialized just after the variable allocation/creation.
5. Global functions like add, sub and print are function they would be eventually linked to the class's function pointers. Process or step of assigning a function address to function pointers is called as ATTACH. Macro ATTACH does the function pointer assignment. AXS is a short form of 'ACCESS' meaning to access a data member or member function.
6. To access the data members we can use standard 'dot' operator in C with the structure variable.
7. To call a member function of A using an object (here in example 'aa') we need to use this syntax obj.functionptr(address of obj)
8. In this implementation all member functions should have atleast one argument of type struct A *. For uniformity we can specifically have it as struct A *this_ptr. This pointer (address of calling object) is used to access object's (aa's and ab's) data members or member functions.
9. Why this model is similar to Object Oriented Programming model? In this model the memory entities 'aa' and 'ab' are actually two objects of type 'A' ('A' can be considered as a class). Both the objects have their own data members and member functions (member functions are actually shared between all objects).
10. Other Possiblities: This model can be extended wherein we can selectively change one or more member function pointers to point to some other functions. Thus, will enable us to change the behavior of an object selectively. For instance, which means that aa's 'add' function could be adding variables 'a' and 'b' into 'c' (c=a+b) and at the same time ab's 'add' function could be adding squares of 'a' and 'b' into c (c=axa + bxb). This behavior is called as 'Function Overriding'.
11. Using data member pointers we can as well simulate 'static' variables (for both data members and member functions) similar to class (like in C++). These pointer variables (or logical static variables) would need to be initialized after all object creations.
Code Section
struct A
{
int a,b;
int c;
int (*add)();
int (*sub)();
int (*print)();
};
#define ATTACH_ALL_FOR_A(obj) {ATTACH(obj,add);ATTACH(obj,sub);ATTACH(obj,print);}
#define THIS this_ptr
#define DECLARE_THIS (*THIS)
#define AXS(X) (THIS->X)
#define ATTACH(obj,function) obj.function = function;
void print(struct A DECLARE_THIS)
{
printf("\nA: %d, B: %d, C: %d",AXS(a),AXS(b),AXS(c));
}
void add(struct A DECLARE_THIS)
{
AXS(c) = AXS(a) + AXS(b);
AXS(print(THIS));
}
void sub(struct A DECLARE_THIS)
{
AXS(c) = AXS(a) - AXS(b);
}
void main()
{
struct A aa,ab;
clrscr();
ATTACH_ALL_FOR_A(aa);
ATTACH_ALL_FOR_A(bb);
aa.a=4;
aa.b=1;
aa.add(&aa);
printf("aa.c: %d",aa.c);
printf("ab.c: %d",ab.c);
getch();
}