Solved

Modeling structures to objects

Posted on 1998-06-15
8
251 Views
Last Modified: 2010-04-15
Ok, what I want is to model the well known struct to objects, including into these pointers to the operations,
somehting like this:

typedef struct o_Some{

   /*Attributes*/
   t_Some r;
   o_List    o;      /*Other object like this*/
   char      fn[90];
   
   /* Operations*/
   int (*Init)(o_Some *Self);
   int (*Done)(o_Some *Self);
   int (*Load)(o_Some *Self, int Idx);
   int (*Save)(o_Some *Self);
   }o_Some;

But what I want is some method to avoid passing all operations the address of the Object. Is there any
way to resolv the address from the caller structure?, Or any other way to program objects in C standard?,
I am currently using gcc into a Linux Box!

Thank you in advance,
0
Comment
Question by:trickle
  • 4
  • 3
8 Comments
 
LVL 11

Accepted Solution

by:
alexo earned 200 total points
ID: 1251218
It is not possible to avoid passing the pointer to the "object".

Consider C++ for example.  Every method has a hidden pointer argument that points to the current object (the "this" pointer, similar to your "Self").  Remember that C++ was initially translated into C.

You can hide the passing of the pointer by a clever use of preprocessor macros but you cannot avoid it.
0
 
LVL 11

Expert Comment

by:alexo
ID: 1251219
The function must get the pointer to the correct structure somehow and the only fail-safe method is to pass it in an argument (on the stack).
0
 
LVL 11

Expert Comment

by:alexo
ID: 1251220
On the other hand, why not use C++?
It already has the mechanism that deals with objects built-in, along with stricter type checking and other goodies.  And, as far as I remember, GCC compiles C++ code.
0
ScreenConnect 6.0 Free Trial

Check out the updates in one game-changing release, ScreenConnect 6.0, based on partner feedback. New features include a redesigned UI that improves session organization and overall user experience. See the enhancements for yourself!

 
LVL 10

Expert Comment

by:RONSLOW
ID: 1251221
It is not clear exactly WHAT 'object' behaviour you are trying to achieve in C .. are you just trying to achieve polymorphism (virtual functions?) .. inheritance? .. classes?

Do you want all your objects to be only struct o_Some instances (same data members), but allow for individual o_Some instances to respond to the methods Init etc differently?  Or do you want to have other structs which are 'derived' from a common struct (eg. o_Some and o_Other each derive from o_Base)?

In either case, don't store ALL the function pointers directly in the object.  Instead, store a POINTER to a strut containing the function pointers.  This way, the table can be shared by multiple objects.

The first case is probably easier, as there is no inheritance involved .. just the one struct.  Try something like this...

struct Methods;

typedef const struct Methods* MethodsPointer;

struct o_Some {
   /*Methods*/
   MethodsPointer call;
   /*Attributes*/
   t_Some r;
   o_List    o;      /*Other object like this*/
   char      fn[90];
} o_Some;

typedef struct Methods {
   int (*Init)(o_Some *Self);
   int (*Done)(o_Some *Self);
   int (*Load)(o_Some *Self, int Idx);
   int (*Save)(o_Some *Self);
} Methods;

Now you can create a Methods object and set it up to point to the appropriate functions.  Then when you create an o_Some object, set the 'call' member to point to a Methods object.

To implement different behaviour for some objects, simply change their 'call' member to point to a DIFFERENT Methods object which is set up with some (or all) of the function pointers pointing to other functions.

eg. in you startup code, you would do
  Methods Standard;
  Methods Special;
  ...
  Standard.Init = Special.Init = xxx;
  Standard.Load = yyy;
  Special.Load = zzz;

Here the Init method (xxx) is shared, but the load method can be different.

Now when you create o_Some instances.
  o_Some x, y;
  x.call = &Standard;
  y.call = &Special;
  x.call->Init(x);
  y.call->Init(y);
  x.call->Load(x,1);
  y.call->Load(y,1);

You can use macros to help get this right.  eg.
  #define CONSTRUCT(_x,_t) _x.call = &_t
  #define CALL(_x,_f) _x.call->_f(_x)
  #define CALL1(_x,_f,_p1) _x.call->_f(_x,p1)
  #define INIT(_x) CALL(_x,Init)
  #define LOAD(_x,p1) CALL1(_x,Load,_p1)
and then say...
  o_Some x,y;
  CONSTRUCT(x,Standard);
  CONSTRUCT(y,Special);
  INIT(x); LOAD(x,1);
  INIT(y); LOAD(y,1);

Another idea is to use a function instead of/ as well as #define macros .. eg.
   int Init (o_Some* Self) {
     return CALL(Self,Init);
   }
you may even get clever, and write a macro to generate these function calls!!  Now you can just say 'Init(x)' .. and better still, 'Init' is a true function .. so you can put it (and expose it) in a library (or dll etc).

Now onto the more complex case of inheritance...

If you want to allow for inheritance, where one 'struct' inherits from another 'struct' and can add its own member variables, then you need to get a little trickier.

eg.
struct Methods;

typedef const struct Methods* MethodsPointer;

struct o_Base {
   /*Methods*/
   union {
     MethodsPointer call;
   } access;
   /*Attributes*/
   t_Some r;
   o_List    o;      /*Other object like this*/
} o_Base;

struct o_Some {
   /*Methods*/
   union {
     MethodsPointer call;
     o_Base base;
   } access;
   /*Attributes*/
   char      fn[90];  /* NOTE: other members are inherited */
} o_Some;

struct o_Other {
   /*Methods*/
   union {
     MethodsPointer call;
     o_Base base;
   } access;
   /*Attributes*/
   int  n;        /* NOTE: other members are inherited */
} o_Other;

typedef struct Methods {
   int (*Init)(void*Self);
   int (*Done)(void*Self);
   int (*Load)(void*Self, int Idx);
   int (*Save)(void*Self);
} Methods;

Note that we need void* because Init can take a o_Base, o_Some or o_Other.  The function itself needs to do a cast (yuck).

now you can set up the function tables for each class...
  Methods Base, Some, Other;
change the macros slightly to use ".access"...
  #define CONSTRUCT(_x,_t) _x.access.call = &_t
  #define CALL(_x,_f) _x.access.call->_f(_x)
  #define CALL1(_x,_f,_p1) _x.access.call->_f(_x,p1)
and you can call like this...
  o_Base b;
  o_Some x;
  o_Other y;
  CONSTRUCT(b,Base);
  CONSTRUCT(x,Some);
  CONSTRUCT(y,Other);
  INIT(b); LOAD(b,1);
  INIT(x); LOAD(x,1);
  INIT(y); LOAD(y,1);
where the approriate function is called depending on the 'class' of the object

The tricks now are that you need to use ".access.base" to get at inherited base class members. eg.
  x.access.base.r
AND you have to cast correctly in your member functions.

You should be able to safely cast from a o_Some to a o_Base as having the union as a first member should ensure that all is ok.

I Hope this helps you.

NOTE:
You may wish to reopen the question before grading and tell us which expert's answers/comments you prefer.  Then the relevant expert can propose an answer for you.

0
 
LVL 11

Expert Comment

by:alexo
ID: 1251222
>> You may wish to reopen the question before grading and tell us which expert's answers/comments you prefer.

Letting the question go stale and the autograder intervene is much easier...
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1251223
Seems to be a trend .. get the info you want then don't bother grading.
0
 

Author Comment

by:trickle
ID: 1251224
Sorry but I'm too busy!. The question was proposed because we are upgrading our DCE with SQL support (I mean ODBC bridge), and all our objects are in C standard and we needed inheritance and polimorphism in a simply way.

The answer I prefer is from RONSLOW, because all possibilities are studied (I mean that just use C++ is not a valid answer for me) and all the capabilities from C++ take place in the exposition from RONSLOW. I'm worry for the delay but I'm too busy (again).
If you have any comments to help us to implement a subsystem message driven (in the network framework), who handles SQL entries and :
   + Generates a new SQL object with the Parser, ..., methods and the Interface to access the Objects DataBase, into a binary packet who is handled from our packet layer where is the scheduler and the timer and the theathing.
   + Send back the answer.

Oh! I'm bothering you...

All the very best.
   

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1251225
Unfortunately you didn't accept/reject an answer in time, and so I missed out on being able to propose my comments as an answer, let alone be rewarded with a grade.

If you did find my answer most helpful, then might I suggest you post another question with a title like "For RONSLOW" that I can answer to get my just desserts.

Regarding your question about implementing this subsystem, it is too large a question and too specific to be added on here .. if you really would like comments on this, please post a new question .. but it would be best to post separate questions for specific problems .. that way you are more likely to get a response.  Hopefully the experts won't be too busy to answer you :-)


0

Featured Post

ScreenConnect 6.0 Free Trial

Discover new time-saving features in one game-changing release, ScreenConnect 6.0, based on partner feedback. New features include a redesigned UI, app configurations and chat acknowledgement to improve customer engagement!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question