• Advertisement
Sign in to follow this  

Interesting thought....

This topic is 4485 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. I am having this thought... Can i combine a bunch of functions in a sort of an object, i mean under "C", and pure "C". Basically, translate this to "C":
class test {
public:
    test();
    void tester(int a);
private:
    int s;
};

Thanks in advance!

Share this post


Link to post
Share on other sites
Advertisement
Function Pointers. Take a look at the Quake 3 source. Its done a lot of times, obviously you wont have inheritance and such, but you can cheat.



struct test
{
void (*test)();
void (*tester)(int a);

int s;
}




Also, my syntax may be wrong, I don't frequently use function pointers.

Share this post


Link to post
Share on other sites
The way to do that is to have a series of global functions which act on a handle to the instance (either a pointer to a struct, or an opaque value).

Share this post


Link to post
Share on other sites
Quote:
Original post by Catafriggm
The way to do that is to have a series of global functions which act on a handle to the instance (either a pointer to a struct, or an opaque value).


Or that...

Share this post


Link to post
Share on other sites
Quote:
Original post by Catafriggm
The way to do that is to have a series of global functions which act on a handle to the instance (either a pointer to a struct, or an opaque value).


Can you please explain a bit more...

Share this post


Link to post
Share on other sites
Quote:
Original post by Ancient Spirit
Quote:
Original post by Catafriggm
The way to do that is to have a series of global functions which act on a handle to the instance (either a pointer to a struct, or an opaque value).


Can you please explain a bit more...



struct test
{
int s;
}

void test_test(test& object)
{
s = 0;
return;
}

void test_tester(test& object, int a)
{
s = a; // ?
return;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Ancient Spirit
i dont think u can use the "&" in "C"


picky picky people, this is what I get for being a pure C++ programmer


struct test
{
int s;
};

void test_test(test* object)
{
object->s = 0;
return;
}

void test_tester(test* object, int a)
{
object->s = a; // ?
return;
}






And I fixed a bug aswell. Now fixed the real bug.

[Edited by - Richy2k on October 9, 2005 7:17:13 PM]

Share this post


Link to post
Share on other sites
No, you can't, but you can replace it by a pointer.

[edit] Fixed at time of writing.
[edit2] And don't forget to actually use the pointer... ->
void test_tester(test* object, int a)
{
object->s = a;
return;
}



jfl.

Share this post


Link to post
Share on other sites
Here are a couple of links that might help.

Object-Oriented C: Creating Foundation Classes Part 1
Object Oriented Programming in C
Object Oriented Programming in C

Here's a complete book on the subject: Object-Oriented Programming With ANSI-C (pdf)

If you want to get an idea of how vtables are constructed, if you have access to a Windows based compiler, open the iunknown.h in a text editor and examine what it does with structures, forward references, and function pointers. You might also have to search for macro definitions in other headers.


Share this post


Link to post
Share on other sites
The easiest transformation from a C++ class to C would be to move the instance variables into a struct. Each of the member functions take a pointer to that struct as an argument (which becomes, effectively, this). I believe that's the same idea used in most C++ compilers to generate code, combined with name mangling to enforce access control.

If you're interested those kinds of techniques, have a look at Portable Object Compiler. It's a preprocessor that converts Objective-C into C.

Share this post


Link to post
Share on other sites
No, you can't. The language doesn't support that kind of syntax.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ancient Spirit
Yea but the thing is that i want to be able to use it as an object...

test t;

t.doFunc();

stuff like that...



It would end up looking like

t->lpVtbl->doFunc(t);

and you would have to initialize the object

test_t *t = NewTObj();

where NewTObj looked something like

test_t * NewTObj(void)
{
test_t *t = malloc(sizeof(*t));
t->lpVtbl = malloc(sizeof(TestVtbl);
t->lpVtbl.doFunc = doFunc;
return t;
}

this would mean that test_t requires a pointer to a vtbl. a vtbl is an structure of function pointers - which might sound ominous but its really just a fancified array of pointers.

typedef struct tagTestVtbl {
... various function pointers
}
TestVtbl;

typedef struct tagTest {
TestVtbl *lpVtbl;
... other stuff
}
test_t;

Treat this as pseudo code - the allocation of the vtbl in NetTObj is kind of funky. Here's a newsgroup thread where I helped a friend with this same kind of question a few years ago: Help with classes. This snippet came from a book I have. This code was part of it's examination of the rudimentary differences between C and C++.


/* virtfunc.c

"C++ Pointers and Dynamic Memory Management"
by Michael Daconta, Wiley & Sons 1995

*/

#include <stdio.h>
#include <stdlib.h>

void stdError(char *str, short fatal)
{
printf("%s",str);
if (fatal)
exit(1);

}

// 0. forward declare the Base "class" typedef
typedef struct Base Base;
typedef Base *Basep;

/* v Table */
typedef struct vTbl vTbl;
typedef vTbl *vTblp;
struct vTbl {
void (*print)(Basep this);
void (*set)(Basep this);

};

// 1. declare the object
/* Simple Base Class */
struct Base {
int A;
void (*construct)(Basep this);
void (*destruct)(Basep this);
vTblp vptr;

};

void construct_Base(Basep this)
{
printf("Calling Base Constructor.\n");
this->A = 0;
this->vptr = (vTblp) malloc(sizeof(vTbl));
if (!this->vptr)
stdError("Allocation Error\n",1);

}

void destruct_Base(Basep this)
{
printf("Calling Base Destructor.\n");
this->A = 0;
free(this->vptr);

}

// 2. initialize the constructor and destructor
// function pointers to the proper functions
Base INITBase = {
0, construct_Base, destruct_Base, 0 };

/* Simple Deriv1 Class */
typedef struct Deriv1 Deriv1;
typedef Deriv1 *Deriv1p;
struct Deriv1 {
Base base;
int B;
void (*construct)(Deriv1p this);
void (*destruct)(Deriv1p this);
void (*print)(Basep this);
void (*set)(Basep this);

};

void print_Deriv1(Basep this)
{
printf("A : %d.\n",this->A);
printf("B : %d.\n",((Deriv1p)this)->B);

}

void set_Deriv1(Basep this)
{
printf("A : ");
scanf("%d",&(this->A));
printf("B : ");
scanf("%d",&(((Deriv1p) this)->B));

}

void construct_Deriv1(Deriv1p this)
{
construct_Base((Basep)this);
this->base.vptr->print = print_Deriv1;
this->base.vptr->set = set_Deriv1;
printf("Calling Deriv1 Constructor.\n");
this->B = 0;

}

void destruct_Deriv1(Deriv1p this)
{
printf("Calling Deriv1 Destructor.\n");
this->B = 0;
destruct_Base((Basep)this);

}

Deriv1 INITDeriv1 = {
{
0,0 }
, 0,construct_Deriv1,destruct_Deriv1,
print_Deriv1, set_Deriv1 };

/* Simple Deriv2 Class */
typedef struct Deriv2 Deriv2;
typedef Deriv2 *Deriv2p;
struct Deriv2 {
Base base;
int C;
void (*construct)(Deriv2p this);
void (*destruct)(Deriv2p this);
void (*print)(Basep this);
void (*set)(Basep this);

};

void print_Deriv2(Basep this)
{
printf("A : %d.\n",this->A);
printf("C : %d.\n",((Deriv2p) this)->C);

}

void set_Deriv2(Basep this)
{
printf("A : ");
scanf("%d",&(this->A));
printf("C : ");
scanf("%d",&(((Deriv2p) this)->C));

}

void construct_Deriv2(Deriv2p this)
{
construct_Base((Basep)this);
this->base.vptr->print = print_Deriv2;
this->base.vptr->set = set_Deriv2;
printf("Calling Deriv2 Constructor.\n");
this->C = 0;

}

void destruct_Deriv2(Deriv2p this)
{
printf("Calling Deriv2 Destructor.\n");
this->C = 0;
destruct_Base((Basep)this);

}

Deriv2 INITDeriv2 = {
{
0,0 }
, 0,construct_Deriv2,destruct_Deriv2,
print_Deriv2, set_Deriv2 };

int main()
{
Deriv1 ob1;
Deriv2 ob2;
Basep bp1, bp2;
ob1 = INITDeriv1;
ob2 = INITDeriv2;
ob1.construct(&ob1); // 3. call constructor
ob2.construct(&ob2);

bp1 = (Basep) &ob1;
bp2 = (Basep) &ob2;

printf("Base Pointer->Deriv1 Object.\n");
bp1->vptr->set(bp1);
bp1->vptr->print(bp1);
printf("\n");

printf("Base Pointer->Deriv2 Object.\n");
bp2->vptr->set(bp2);
bp2->vptr->print(bp2);

ob1.destruct(&ob1);
ob2.destruct(&ob2);

return 0;
}




And IUnknown from COM illustrates the interface portion of the above with a small vtable.


Here is the IUnknown interface. All COM objects must implement this.

typedef struct IUnknown IUnknown;
typedef struct IUnknownVtbl {
HRESULT (__stdcall *QueryInterface)(IUnknown *, REFIID, void **);
ULONG (__stdcall *AddRef)(IUnknown *);
ULONG (__stdcall *Release)(IUnknown *);
} IUnknownVtbl;

struct IUnknown { struct IUnknownVtbl *lpVtbl; };

#define IUnknown_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IUnknown_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IUnknown_Release(This) (This)->lpVtbl->Release(This)

These macros don't have to be used, but they illustrate how the methods are
called. One thing to note regarding IUnknown and COM is that only the
interface is exposed. The data items of the "class" are hidden inside the
implementation file. Take a look at the comlib example at John's website
(http://www.john.findlay1.btinternet.co.uk/OLE/ole.htm) for details. In
contrast, a C++ class definition contains the data members, in similar
fashion to the tagQ structure definition that I wrote.




The note at the bottom of that source is old - the url it mentioned has changed. It's now OLE & COM. ComLib is the second item on that page.

Here are a few more related links.

Faking Templates In C
Object-oriented programming in C
Object-oriented programming using C

Share this post


Link to post
Share on other sites
Quote:
Original post by Ancient Spirit
Yea but the thing is that i want to be able to use it as an object...

test t;

t.doFunc();

stuff like that...


As much as I hate C++ (Although RAII does call to me), it was created for a reason. I have to ask, why not use it?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement