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