|
From: Dan P. <ba...@al...> - 2005-12-04 16:59:43
|
On Dec 4, 2005, at 8:21 AM, Sam Steele wrote:
> Right now I'm keeping my own std::list<Entity *> of Entity pointers
> so I don't lose them when they turn into Drawables in the list, but
> I'm guessing RTTI would let me enumerate genmenu's m_scene to find
> Entity-derived objects, and cast them from a Drawable pointer to an
> Entity pointer to use the Entity-specific functions?
Yes. You can take any pointer and try to upcast it to any other
pointer, and if it's possible it'll give you the new pointer;
otherwise it'll return NULL. If you do the same with an object or a
reference, it'll throw an exception if it fails.
One thing to be clear about, dynamic_cast is most useful for
upcasting or cross-casting (which I think is what you want to do
here). For example:
A -> B -> C
X -> Y /
What my bad ASCII art there is saying is that B derives from A, Y
derives from X, and C derives from B and Y. In this case, you ought
to be able to cast a C to any of those things without any RTTI
voodoo. You can also take an A* which is actually a C, and up-cast it
to a C; RTTI lets you do this safely, if you don't know the A is a C
already. Similarly if you have an X* which is actually a C, you can
use RTTI to upcast to C, and I think you might be able to cross-cast
to A or B (maybe with an intermediate C* cast), but again that's not
too safe without using RTTI to check.
> create_object("Paddle") returns an Entity* which is pointing to a
> Paddle*. If I then call ent->loadFromFile(), then
> Entity::loadFromFile() gets called, but not Paddle::loadFromFile
> (). I think that's what the virtual keyword is for? Anyway, for
> now I just have a second giant if/else called load_object() that
> calls loadFromFile before the object gets cast to an Entity*.
If I'm understanding correctly, it sounds like one way or another the
compiler isn't seeing the virtual applying to what you're applying it
to. That's the behavior you'd get if you had some method in both
classes without 'virtual'. Another way this can happen is if you try
to use it from the constructor. Calling virtuals from the constructor
is a bad idea (ditto with the destructor). If you think about it for
a minute you can see why. :) They made the language patch up the
vtable at each step of construction/destruction to make this not as
bad as it could be, but IMO they should've just made it illegal...
Also the base class must be called explicitly from the derived
method. This lets you wholly override functionality from a base class
and also have better control over when the base class method gets
called (before or after, etc). Unfortunately there's no smart way in C
++ to address the base class. So somewhere in your
Paddle::loadFromFile() you need to have something like
"Entity::loadFromFile()".
> Now, m_light gets assigned a pointer in a linked list of where
> lights are located (to make finding them as fast as possible for
> vertex lighting). Anyway, it gets a value inside of Light();, but
> as soon as it returns from that call, it goes back to being NULL
> again before loadFromFile gets called. Is there another way I'm
> supposed to call the default constructor from another constructor?
AFAIK you can't call another constructor on the same object directly
(someone correct me here if I'm wrong, because I'm a little fuzzy on
this point). The standard idiom is this:
class Foo {
public:
Foo();
Foo(int a);
Foo(int a, int b);
private:
void init(int a, int b);
};
Foo::Foo() {
init(defa, defb);
}
Foo::Foo(int a) {
init(a, defb);
}
Foo::Foo(int a, int b) {
init(a, b);
}
void Foo::init(int a, int b) {
// Real constructor guts
}
|