EC++
Andras Tantos
andras_tantos at yahoo.com
Thu Feb 12 05:30:34 CET 2004
Hi!
> > Ugy erted, hogy a class, az egy struktura, aminek van egy plusz
> > 'lathatatlan' eleme, ami a virtual fuggveny-tablara mutat, nem? A
>
> Specialisan a BOOPSI-ban egyetlen fuggveny, mely bemenetkent megkap
> egy-egy mutatot a class-ra, az objektumra, es a metodusra.
> A fuggveny flash-ban van, mert mashol nem is lehet vegrehajthato kod.
> A fuggveny cimet at lehet irni, csinalhatsz subclass-t, ami atveszi a
> metodusok vegrehajtasat, de akar tovabb is passzolhatja a superclass-nak.
Lehet, hogy nem ertem a microd minden specialitasat, de miert kell meg egy
fuggvenyhivas? Vagy a proci nem tud indirekt fuggvenyhivast?
> > C++ osztalyok hasznalata nem igenyel feltetlnul dinamikus memoriat. Az
> > exception-handling mar fordito-fuggo, a GCC-ben pl. igen.
>
> Ha letre kell hozni egy objektumot, akkor memoriat kell neki foglalni,
> ha el akarod dobni, fel kell szabaditani. Tehat valamilyen formaban
> megis csak kell a dinamikus memoriakezeles...
Letre lehet oket hozni az adatszegmensen (statikusan) es a veremben is
(automatikisan). A felszabaditas automatikusan megtortenik, amikor a valtozo
kikerul a 'scope'-bol, illetve a program terminalasakor. Nem kell dinaikus
memoria C++ class-ok hasznalatahoz. Ebbol a szempontbol nincs kulonbseg a C
strukturak es a C++ osztalyok kozott.
Na, vettem a fardtsagot es osszeutottem egy kis C programot, ami ket osztaly
deklaral es hasznal. Nem a legszebb a kod, biztos lehetne elegansabban is,
meg nehany #define-nal szepiteni, de a lenyeget most nem ez. Amit ez a
program csinal, az a C++ (es mellesleg TurboPascal) fele objektum-leiras. Ez
a megoldas jol mukodik egeszen a tobbszoros leszarmazas bevezeteseig. Ha
valami nem vilagos, kerdezz, megprobalom elmagyarazni...
#include <stdio.h>
#include <malloc.h>
/* Types of virtual methods, defined later */
typedef void (*Method1_Type)(void *ThisPtr, char *String);
typedef int (*Method2_Type)(void *ThisPtr, char *String, int Param);
typedef void (*Method3_Type)(void *ThisPtr, char *String, float Param);
typedef int (*Method4_Type)(void *ThisPtr, char *String);
/* Class_A */
/* ------- */
/* Typedef for the table of virtual methods */
typedef struct {
Method1_Type Method1Ptr;
Method2_Type Method2Ptr;
} ClassA_VirtualMethodTable_Type;
/* This is the actual object structure that gets duplicated for each
instance of the class */
typedef struct {
ClassA_VirtualMethodTable_Type *_Vtbl;
int Member1;
char *Member2;
} ClassA;
/* Method definitions for ClassA */
void ClassA_Method1(void *ThisPtr, char *String) {
ClassA *This=(ClassA*)(ThisPtr);
printf("\tClassA_Method1(\"%s\")\n",String);
printf("\t\tcalled for object at 0x%08x\n",This);
printf("\t\tMember1: %d\n",This->Member1);
printf("\t\tMember2: %s\n",This->Member2);
}
int ClassA_Method2(void *ThisPtr, char *String, int Param) {
ClassA *This=(ClassA*)(ThisPtr);
printf("\tClassA_Method2(\"%s\",%d)\n",String,Param);
printf("\t\tcalled for object at 0x%08x\n",This);
printf("\t\tMember1: %d\n",This->Member1);
printf("\t\tMember2: %s\n",This->Member2);
/* Here we call back another virtual method of the classs */
This->_Vtbl->Method1Ptr(ThisPtr,"-- called from ClassA_Method2");
}
/* This is actually a static method for ClassA */
void ClassA_Method3(void *ThisPtr, char *String, float Param) {
ClassA *This=(ClassA*)(ThisPtr);
printf("\tClassA_Method3(\"%s\",%f)\n",String,Param);
printf("\t\tcalled for object at 0x%08x\n",This);
printf("\t\tMember1: %d\n",This->Member1);
printf("\t\tMember2: %s\n",This->Member2);
/* But we still can call virtual methods out of it */
This->_Vtbl->Method1Ptr(ThisPtr,"-- called from ClassA_Method3");
}
/* Static virtual method table. Will be allocated once for all objects of
ClassA, on the data segment */
ClassA_VirtualMethodTable_Type ClassA_VirtualMethodTable = {
ClassA_Method1,
ClassA_Method2
};
/* This is how you would create an object instance of ClassA on the heap */
ClassA *New_ClassA(int Member1, char *Member2) {
ClassA *Object = (ClassA *)malloc(sizeof(ClassA));
Object->Member1 = Member1;
Object->Member2 = Member2;
Object->_Vtbl = &ClassA_VirtualMethodTable;
return Object;
}
/* However you can create them statically on the datasegment too */
ClassA Static_ClassA_Object = {
&ClassA_VirtualMethodTable,
3,
"Static object"
};
/* ClassB (it inherits from ClassA) */
/* -------------------------------- */
/* Again, a typedef for the virutal method table */
typedef struct {
/* Virtual methods in ClassA */
Method1_Type Method1Ptr;
Method2_Type Method2Ptr;
/* new virtual method defined only in ClassB */
Method4_Type Method4Ptr;
} ClassB_VirtualMethodTable_Type;
/* And the structure that holds the class values */
typedef struct {
/* New virtual table */
ClassB_VirtualMethodTable_Type *_Vtbl;
/* These must be the same as ClassA */
int Member1;
char *Member2;
/* New members only for ClassB */
char *NewMember;
} ClassB;
/* Method definitions for ClassB */
void ClassB_Method1(void *ThisPtr, char *String) {
ClassB *This=(ClassB*)(ThisPtr);
printf("\tClassB_Method3(\"%s\")\n",String);
printf("\t\tcalled for object at 0x%08x\n",This);
printf("\t\tMember1: %d\n",This->Member1);
printf("\t\tMember2: %s\n",This->Member2);
printf("\t\tNewMember: %s\n",This->NewMember);
}
int ClassB_Method4(void *ThisPtr, char *String) {
ClassB *This=(ClassB*)(ThisPtr);
printf("\tClassB_Method4(\"%s\")\n",String);
printf("\t\tcalled for object at 0x%08x\n",This);
printf("\t\tMember1: %d\n",This->Member1);
printf("\t\tMember2: %s\n",This->Member2);
printf("\t\tNewMember: %s\n",This->NewMember);
return 4;
}
/* And the virtual method table. Note that we override Method1 but not
Method2 */
ClassB_VirtualMethodTable_Type ClassB_VirtualMethodTable = {
ClassB_Method1,
ClassA_Method2,
ClassB_Method4
};
/* Again, this is how you would create an instance on the heap */
ClassB *New_ClassB(int Member1, char *Member2,char *NewMember) {
ClassB *Object = (ClassB *)malloc(sizeof(ClassA));
Object->Member1 = Member1;
Object->Member2 = Member2;
Object->NewMember = NewMember;
Object->_Vtbl = &ClassB_VirtualMethodTable;
return Object;
}
/* Though you don't have to... */
ClassB Static_ClassB_Object = {
&ClassB_VirtualMethodTable,
13,
"Static object B",
"this is really not ClassA"
};
/* Main application */
int main() {
printf("Call a virtual method on ClassA. It will end up calling
ClassA_Method2,\n");
printf("which will call ClassA_Method1\n\n");
Static_ClassA_Object._Vtbl->Method2Ptr(
&Static_ClassA_Object,
"Called from main",
52
);
printf("\n\nNow, let's call a static method. The first call is
trivial,\n");
printf("but it will end up calling ClassA_Method1\n\n");
ClassA_Method3(
&Static_ClassA_Object,
"called from main too",
3
);
printf("\n\nNow lets move on to the derived class.\n");
printf("Call the new virtual method first. You'll note that it will call
ClassB_Method4\n\n\n");
Static_ClassB_Object._Vtbl->Method4Ptr(
&Static_ClassB_Object,
"Called from main for ClassB"
);
printf("\n\nNow, we call Method2.\n");
printf("Note, even though we're seem to be calling a method for
ClassB,\n");
printf("we will end up calling ClassA_Method2, just as before.\n");
printf("This method however now will call ClassB_Method1 since,\n");
printf("we've overridden that virtual method\n\n");
Static_ClassB_Object._Vtbl->Method2Ptr(
&Static_ClassB_Object,
"Called from main for ClassB too",
52
);
printf("\n\nFinally let's see how to call a static base-method\n");
printf("Notice that the static method will still call the correct
ClassB_Method1,\n");
printf("instead of ClassA_Method2\n\n");
ClassA_Method3(
&Static_ClassB_Object,
"Still calling from main",
45
);
return 0;
}
Udv,
Tantos Andras
<http://andras.tantos.homedns.org>
More information about the Elektro
mailing list