Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

curious about polymorphism in C++

Name: Anonymous 2007-01-06 15:08

I'm curious how polymorphism in C++ ends up being compatible with the way arrays work internally in the language.  Here's an example:

//===========================================================
#include <cstdio>

class BaseClass {
public:
    int a, b, c;
    float d;

    BaseClass() : a(5), b(2), c(9), d(1.432) {  };
    ~BaseClass()  {  };

    virtual void print(void) const;
};

void BaseClass::print(void) const
{
    printf("I am BaseClass -- a = %d, b = %d, c = %d, d = %f\n", a, b, c, d);
}

// =============================================================================
class AClass : public BaseClass {
public:
    int e, f, g;
    double zzz, xxx;

    AClass() : e(40), f(50), g(60), zzz(154389.432292), xxx(394.9999282) {  };
    ~AClass()  {  };

    virtual void print(void) const;
};

void AClass::print(void) const
{
    printf("I am AClass -- a = %d, b = %d, c = %d, d = %f\n", a, b, c, d);
    printf("               e = %d, f = %d, g = %d\n", e, f, g);
    printf("               zzz = %f, xxx = %f\n", zzz, xxx);
}

class BClass : public BaseClass {
public:
    int z;
    char *str;

    BClass() : z(-5), str("BClass->str...") { };
    ~BClass() {  }

    virtual void print(void) const;
};

void BClass::print(void) const
{
    printf("I am BClass -- a = %d, b = %d, c = %d, d = %f\n", a, b, c, d);
    printf("               z = %d, str = %s\n", z, str);
}

int main(void)
{
    BaseClass **array = new BaseClass*[3];

    array[0] = new BaseClass();
    array[1] = new AClass();
    array[2] = new BClass();

    printf("sizeof(BaseClass) = %d, (AClass) = %d, (BClass) = %d\n", sizeof(BaseClass),
            sizeof(AClass), sizeof(BClass));
    printf("sizeof(*array[0]) = %d, (*array[1]) = %d, (*array[2]) = %d\n", sizeof(*array[0]),
            sizeof(*array[1]), sizeof(*array[2]));

    for (int i = 0; i < 3; i++)
        array[i]->print();
}

//============================================================

It outputs as follows:

sizeof(BaseClass) = 20, (AClass) = 48, (BClass) = 28
sizeof(*array[0]) = 20, (*array[1]) = 20, (*array[2]) = 20
I am BaseClass -- a = 5, b = 2, c = 9, d = 1.432000
I am AClass -- a = 5, b = 2, c = 9, d = 1.432000
               e = 40, f = 50, g = 60
               zzz = 154389.432292, xxx = 394.999928
I am BClass -- a = 5, b = 2, c = 9, d = 1.432000
               z = -5, str = BClass->str...


Okay, it seems to Just Work but how?  Why doesn't the 48-byte chunk of stuff in array[1] clobber what's in array[2]?  I know all BaseClass objects are 20 bytes and it seems to store each object in the array as -that-, but considering it in that perspective, how does the program "know" array[1] is an AClass object and array[2] is a BClass object?

I'm guessing the way it works properly involves storing the data for these objects in a non-contiguous way, no?

I'm just trying to get an idea of what the limits of polymorphism are in C++, by that I mean the technical limits.  I mean, for all intents and purposes, I've technically made a heterogenous array, something I thought wasn't possible in C++.

Once again I learn something new every day about this language I've been using for over 6 years.  I just wish I knew about this sooner instead of letting my assumptions about internals stop me from trying this.  I saw this done in a C# book and I was like, "tomorrow morning I'm going to try that in C++ and see if it works" and sure enough it does.

But... WHY does it work?

Name: Anonymous 2007-01-06 15:13

how does the program "know" array[1] is an AClass object and array[2] is a BClass object

It doesn't know and it can't know. BUT if you call a virtual function, the good type of subclass will be called because of the late-binding created during compile time. That's why there is a huge bug in your code: put all your destructors virtual or it won't be called and your objects won't be properly destroyed if you have this kind of thing:
Base *b = new Derived;
delete b;

Name: Anonymous 2007-01-06 15:35

>>2

Duly noted.  I'm going to tinker with this stuff a bit more before making some seriously-needed overhauls to my game.

Because of my ignorance as to this being possible, I made some cruder approaches to problems in my project's code.  In the game, something could be represented by a mesh, a sprite, or a skeletal-animated mesh.  I wanted to store all these object types in my scene graph but didn't know how powerful polymorphism was, so I ended up making a class called "Simulacrum" that stored a pointer to a Mesh, a pointer to a Sprite, and a pointer to a SkelModel, and then like "if objtype is MESH  then call meshptr->draw()", "if objtype == SPRITE then call spriteptr->draw()", etc...

I'm guessing now I can get rid of the Simulacrum class as bad design (normally I give myself elbow room for "bad" design, but this was really causing problems I don't want to get into right now) and write a VisualNode class and make Sprite, Mesh, and SkelModel derive from it and put virtual functions to good use.

Sigh... overhaul time.

What are some "don't"s and pitfalls of polymorphism in C++ I should be aware of when I make this sweeping change, other than the one you mentioned?

Name: Anonymous 2007-01-06 20:04

you can look into it with some memory hex dump tools ord debugger.

But the array consists of pointers (4 byte), the sizeof operator is just returning size of the base class not the size of the actual size of the elements.

The actual size you would get if you cast the elements before the sizeof operator to the right class.

You could also use a void** array... would be the same.

Name: Anonymous 2007-01-06 20:04

Also, stuff in the array doesn't get "clobbered", because it is an array of pointers, and all pointers are the same size.

Name: Anonymous 2007-01-06 21:50

>>5

oh shi-

You have no idea how red my embarassed face is right now for not having noticed that ;_;

Name: Anonymous 2007-01-08 7:49

bump

Name: Anonymous 2010-11-25 19:58

Name: Anonymous 2010-12-24 4:12

Name: Anonymous 2011-01-31 21:35

<-- check em dubz

Name: tray 2012-03-15 16:23

hey ya all, guten tag!

Name: Sgt.Kabu嘢勒kiman匔䁜 2012-05-28 21:57

Bringing /prog/ back to its people
All work and no play makes Jack a dull boy
All work and no play makes Jack a dull boy
All work and no play makes Jack a dull boy
All work and no play makes Jack a dull boy

Don't change these.
Name: Email:
Entire Thread Thread List