![]() |
|
Pointer Hell Between Base/Derived Classes |
Kris Asick
Member #1,424
July 2001
|
Although I don't have a problem anymore, I would like an explanation regarding the following headaches I went through. I learned something interesting today... I'll bet a lot of you C++ programmers know this already but finding it out suddenly made things easier: Pointers to arrays of objects derived from a base class != Pointers to arrays of objects of the base class In making my game engine, one of the things it relies on is being able to make derived classes for sprites, map tiles, etc., without having to have those classes programmed into the engine itself, which itself isn't very difficult, but the engine needs to be able to store and access those derived objects, which was the not-so-simple part, made worse for things like map tiles which are stored in 2D arrays. In trying to make this work, I kept running into crashes, constantly. I eventually started comparing pointers and discovered that the arrays of derived-object pointers, in being converted to arrays of base-object pointers, were no longer the same as before... rather, the base-object pointers were as though the array had been made out of base objects instead of derived objects. So when communicating derived objects to base objects, I couldn't find any way to do it at an object or array level, I had to work solely with pointers, otherwise the object data is improperly interpreted in the base class object as a result of the base class generally being smaller (for memory usage) than the derived class. To put this in perspective, here are two pieces of code. The first one doesn't work. The one below does. From my perspective, it should seem like both should work, but only the bottom one does.
---
I should also note that both compile. I only vaguely understand why this is as it is, so if someone could spell out a bit better why the top code block fails and the bottom one doesn't, it would be appreciated. --- Kris Asick (Gemini) --- Kris Asick (Gemini) |
Michael Faerber
Member #4,800
July 2004
![]() |
I would like to ask you simple question: Why don't you simply use std::vector? I think this could save you from troubles like this ... -- |
chidj06
Member #7,844
October 2006
![]() |
This is the way in which polymorphism works, the whole system is based arround pointers and dynamic allocation. A pointer to of object type pointer-to-base class can point to the base class, or any derived classes. i.e you need to use the new, delete keywords, or assign the pointer the address of a valid(ie. class or subclass) object. But if you declare as an explicit object (non pointer, therefore no dynamic alloction) object is immediately tied to one in memory. Base_Class* object; object = new Base_Class; ... or object = new Derived_Class;
|
Kris Asick
Member #1,424
July 2001
|
Quote: I would like to ask you simple question: Why don't you simply use std::vector? I think this could save you from troubles like this ... The thought of having to pass a vector of vectors of pointers to derived objects to a function induces pain. I do use vectors for some things, nothing that complicated though. --- Kris Asick (Gemini) --- Kris Asick (Gemini) |
Jakub Wasilewski
Member #3,653
June 2003
![]() |
Quote: &in_array[z][zz]; The problem lies in this statement. in_array[z] is a B_OBJECT*, which is basically the same as a B_OBJECT[] - a one dimensional array. The problem is that the final [zz] uses pointer arithmetic only - and the arithmetic has no way to know that this is actually an array of D_OBJECTs. So, the address is calculated as follows: start_address_of_in_array_z + zz * sizeof(B_OBJECT) This is obviously wrong - but pointer arithmetic is based only on the type of the pointer, not the type of the actual objects within. So, why does the second approach work? Because, unlike B_OBJECT and D_OBJECT, B_OBJECT* and D_OBJECT* are actually the same size, so the indexing operation [zz] returns the proper address regardless of the actual type being pointed to. --------------------------- |
Michael Faerber
Member #4,800
July 2004
![]() |
Quote: The thought of having to pass a vector of vectors of pointers to derived objects to a function induces pain. I do use vectors for some things, nothing that complicated though. It's not really THAT complicated - look: void Function(std::vector<std::vector<DerivedObject*> > objs); // compared to: void Function(DerivedObject*** objs); And if you want to avoid the copying of vectors (which happens automatically due to passing the vector to the function), just use a reference to a vector: void Function(std::vector<std::vector<DerivedObject*> >& objs); That should give you a nice performance, too. -- |
X-G
Member #856
December 2000
![]() |
I know this isn't really an answer to your question, but I think that a lot of the headache and confusion you're experiencing now could be easily avoided by not employing technological terrors like the ones in your code samples there in the first place. Rethink your design and how components fit together, and hopefully the solution should become clear. -- |
nonnus29
Member #2,606
August 2002
![]() |
I don't understand why you think that approach would work. If you allocate an array of b_objects, your going to get an array of b_objects. How is the compiler supposed to know you actually wanted an array a particular (out of possibly many) subclass? I agree with X-G, you're using C++ as 'C + Objects'. As you can see that's not a good approach. If you'd use containers like the others said you wouldn't have these problems. |
Audric
Member #907
January 2001
|
99% of times, what you actually want to put in an array / N-dimension array / STL container is a reference to something. A pointer to a BITMAP, a pointer to a B_OBJECT, etc. |
Kris Asick
Member #1,424
July 2001
|
All of you affirmed my reason for asking. I didn't quite understand what was happening, and now I do. Thanks, guys! --- Kris Asick (Gemini) --- Kris Asick (Gemini) |
|