🔒 Locked
convert interfaces to derived objects.
Advertisement
Original Post
Hello, hello, hello. Pertaining to the headline, is it common to store something like a flag into an interface, which gives information about the derived class/used object. An example: Imagine, there is an array of std::vector, specifing an array of IObject pointers. Somthing like: std::vector< IObject* > ... IObject is the interface, the abstract class. Now, there are three derived classes from this interface. CSolarSystem CPlanet CObjcet Now, that array, which I mentioned before, is mixed with these objects, all derived from IObject. Should I place an flag, lets say dwObjType into IObject to reveal the true class-object saved in that array? Thanks Alex
1° This is bad design. One generally shouldn't be doing this at all. You're willingly losing the type of the object, and then trying to retrieve it: that's like digging holes to fill them afterwards. It would be better to use the interface for what it is and use virtual functions.
2° If you do really need this (why?), use dynamic_cast. It does exactly what you want, but takes less effort and is always safe, even when you screw up.
3° If for some obscure religious reason, you do not want to use dynamic_cast, do not use a type variable: it adds unnecessary memory overhead, is type-unsafe, takes a lot of code to write and also is ugly. Use virtual functions to perform the type-casting in a fashion similar to dynamic_cast
In short: using a "type" member variable is never useful, there's always a better method.
2° If you do really need this (why?), use dynamic_cast. It does exactly what you want, but takes less effort and is always safe, even when you screw up.
3° If for some obscure religious reason, you do not want to use dynamic_cast, do not use a type variable: it adds unnecessary memory overhead, is type-unsafe, takes a lot of code to write and also is ugly. Use virtual functions to perform the type-casting in a fashion similar to dynamic_cast
In short: using a "type" member variable is never useful, there's always a better method.
Hi ToohrVyk.
IObject is an interface, because I want have more than one object with the same behaviour and properties. For example there are objects like the camera, a solar system, a planet, a space ship, or what ever.
Sure, IObject has common functions, for example, RotationX, RotationY, MoveTo, AlignTo, or any function which can be used for the mentioned objects.
But functions like Initialize, Release, DrawObj are virtual functions.
To 2° : So, the reason why I need this is the following:
I´m up to implement a scene manager with an occtree as the spacial manager.
Imagine you place a solar system in this octree. this solar system should be very huge, with many planets loaded. Those planets by the way, are also put into this octree, with a slight difference. Planets are the lesser one of that two.
This means, the planet must rotate around the center of that solarsystem, even every plantet put in. So, when you traverse the octree, the objects, which are passed through the way down, must be tested if they are possible central stars, because the lesser objects must rotate around that.
But another question, how can you cast an interface object to an other object, which it really is? I mean, how do you know this information, when not from an type variable? Is it dynamic_cast. When it is so, than I have found out the reason why it exists.
I have never use dynamic_cast, and I won´t ;)
So you think its bad to use a type variable?
Thanks
Alex
IObject is an interface, because I want have more than one object with the same behaviour and properties. For example there are objects like the camera, a solar system, a planet, a space ship, or what ever.
Sure, IObject has common functions, for example, RotationX, RotationY, MoveTo, AlignTo, or any function which can be used for the mentioned objects.
But functions like Initialize, Release, DrawObj are virtual functions.
To 2° : So, the reason why I need this is the following:
I´m up to implement a scene manager with an occtree as the spacial manager.
Imagine you place a solar system in this octree. this solar system should be very huge, with many planets loaded. Those planets by the way, are also put into this octree, with a slight difference. Planets are the lesser one of that two.
This means, the planet must rotate around the center of that solarsystem, even every plantet put in. So, when you traverse the octree, the objects, which are passed through the way down, must be tested if they are possible central stars, because the lesser objects must rotate around that.
But another question, how can you cast an interface object to an other object, which it really is? I mean, how do you know this information, when not from an type variable? Is it dynamic_cast. When it is so, than I have found out the reason why it exists.
I have never use dynamic_cast, and I won´t ;)
So you think its bad to use a type variable?
Thanks
Alex
Quote:
I have never use dynamic_cast, and I won´t ;)
That's a pretty bold statement considering you don't seem to know what it is ;)
for (std::vector<IObject*>::iterator i = objects.begin(); i != objects.end(); ++i){ // see if we have a planet CPlanet* planet = dynamic_cast<CPlanet*>(*i); if (planet != 0) { // we have a planet planet->DoSomePlanetOnlyThing(); }}But it sounds like what you really want is some sort of heirarchical relationship between your objects. That would be more the realm of a scene graph. In that case your planets become children of the star they are orbiting. All of their transformations are then performed in the coordinate system of their parent, and thus always remain in a position relative to their parents in the scene.
Quote:
To 2° : So, the reason why I need this is the following:
I´m up to implement a scene manager with an occtree as the spacial manager.
Imagine you place a solar system in this octree. this solar system should be very huge, with many planets loaded. Those planets by the way, are also put into this octree, with a slight difference. Planets are the lesser one of that two.
This means, the planet must rotate around the center of that solarsystem, even every plantet put in. So, when you traverse the octree, the objects, which are passed through the way down, must be tested if they are possible central stars, because the lesser objects must rotate around that.
Your deadly sin is: separation of responsibility. Your modules or classes do too many things at once. Your renderer handles logic, your scene manager manages planetary information. A correct design approach would be to allow visible objects to orbit around one another (a typical responsibility of transform objects, which would be a natural part of a scene manager), and then allow the planets to describe themselves as a hierarchy of transforms and meshes. This removes the cast problem from the equation, and also ensures that you can modify the renderer without having to alter the planets or vice versa.
Quote:
But another question, how can you cast an interface object to an other object, which it really is? I mean, how do you know this information, when not from an type variable? Is it dynamic_cast. When it is so, than I have found out the reason why it exists.
Any object with a virtual function has a virtual table, which dynamic_cast can use as a type variable to determine the true object type at runtime. An additional type variable would only waste memory.
Quote:
I have never use dynamic_cast, and I won´t ;)
Interesting. Do you have a valid reason, or is it just a religious issue or psychological block? If the latter, I still strongly advise you against using a type variable.
Quote:
So you think its bad to use a type variable?
It's not bad per se. It's just slow, bug-prone, awkward and useless.
@penwan:
Wow, nice trick.
Maybe I should use this one!!
Is it fast?
Something to the relationship.
It is true that the planets must be calculated relativ to their parent star.
I thought of this as well. Every IObject object has a world matrix saved.
And when I have figured out if a passed object is a central star, I could use that world matrix for further transformation.
Thanks
Alex
Wow, nice trick.
Maybe I should use this one!!
Is it fast?
Something to the relationship.
It is true that the planets must be calculated relativ to their parent star.
I thought of this as well. Every IObject object has a world matrix saved.
And when I have figured out if a passed object is a central star, I could use that world matrix for further transformation.
Thanks
Alex
Quote:
Original post by directNoob
Wow, nice trick.
Maybe I should use this one!!
Is it fast?
The fastest you can get for this particular functionality. However, since in your case you shouldn't even need polymorphism, it's very slow for what you're trying to achieve.
Quote:
Something to the relationship.
It is true that the planets must be calculated relativ to their parent star.
I thought of this as well. Every IObject object has a world matrix saved.
And when I have figured out if a passed object is a central star, I could use that world matrix for further transformation.
An usual way to implement this is to use a spaghetti stack: each object owns a transformation. Each transformation may have a parent. The transformation of an orbiting object has a parent (which is the transformation of the orbit's center). When obtaining the final matrix of a transform, apply the transform, then its parent, and so on.
After you've done this, the approach becomes entirely non-polymorphic (thus, very fast) at rendering time, and also allows nifty things (such as orbiting camera or third-person camera) very easily. The price is the creation and linking together of transforms at loading time.
Quote:
Original post by directNoob
But another question, how can you cast an interface object to an other object, which it really is? I mean, how do you know this information, when not from an type variable? Is it dynamic_cast. When it is so, than I have found out the reason why it exists.
When an object has virtual functions, your compiler has to keep track of the type of the object so as to know which functions to call. dynamic_cast uses that information to safely perform the conversion between a Base and Derived pointer. It is only if you personally know that you are casting between the correct types that static_cast is permissible. C-style casts are definitely out, they just won't do the right thing in these circumstances (q.v. reinterpret_cast).
Adding a type code would be redundant, would add to code maintenance and wouldn't really be any faster. The type variable would only work in combination with an exact type check, while dynamic_cast works with any kind of class hierarchy (e.g. if C derives from B which derives from A, and you have an A* that points to a C, you can cast it to a B*, which a type code wouldn't allow). Even if your needs are limited to such circumstances, you can use typeid to retrieve an object's type information and perform tests on that -- although it is bad style.
Quote:
I have never use dynamic_cast, and I won´t ;)
[rolleyes]
Quote:
So you think its bad to use a type variable?
For most people, dynamic_cast and typeid are sufficient. You aren't in a position to decide whether you need to build your own RTTI framework until you know what they do and how they work. In fact, I'd argue that you aren't qualified to write your own RTTI framework unless you understand how they work.
Heck, in most cases, virtual functions are enough and you don't even need dynamic_cast nor typeid.
Hi ToohrVyk.
Thanks, but allow me to read your posts...
I first have to mirror it on my problem.
But meanwhile I could quickly explane how I thought of the implementation.
The SceneManager manages the objects in an ObjectManager and the objects in the scene in the octree. So I try the following:
In the root node, there is the whole bounding box, the whole of the universe.
And when you travers through that tree, the solar system would stuck very fast. I mean, it would travese just a few iterations, because it is also big.
And the planetes should then come straight after that node in the octree.
And the same with the objects. But you wrote something else.
Let me read it.
Alex
Thanks, but allow me to read your posts...
I first have to mirror it on my problem.
But meanwhile I could quickly explane how I thought of the implementation.
The SceneManager manages the objects in an ObjectManager and the objects in the scene in the octree. So I try the following:
In the root node, there is the whole bounding box, the whole of the universe.
And when you travers through that tree, the solar system would stuck very fast. I mean, it would travese just a few iterations, because it is also big.
And the planetes should then come straight after that node in the octree.
And the same with the objects. But you wrote something else.
Let me read it.
Alex
Ok ok. I´ll use dynamic_cast... :D
@Fruny:
Ok, when I´m not able to write something like RTTI, I better should use
dynamic_cast. I haven´t needed it before.
Thanks for that explanation.
Alex
@Fruny:
Ok, when I´m not able to write something like RTTI, I better should use
dynamic_cast. I haven´t needed it before.
Thanks for that explanation.
Alex
Quote:
An usual way to implement this is to use a spaghetti stack: each object owns a transformation. Each transformation may have a parent. The transformation of an orbiting object has a parent (which is the transformation of the orbit's center). When obtaining the final matrix of a transform, apply the transform, then its parent, and so on.
This is exacly my point!
Every child got a pointer of its parent node plus that pointer of the next central star.
Because out solar system is rotating around something and the earth is rotating around the sun again and the moon again is rotating around the earth and last but not least, a simple object could rotate around any object...
Simple. One can imagine the hirarchical structure.
Quote:
After you've done this, the approach becomes entirely non-polymorphic (thus, very fast) at rendering time, and also allows nifty things (such as orbiting camera or third-person camera) very easily. The price is the creation and linking together of transforms at loading time.
But the polymorthism I just use for multible classes which have the same properties, as I said. Why shouldn´t I use polymorphism?
It´s absolutely suitable. But it is a bit more complex.
The draw function could later be used for OpenGl or another graphics API.
The only thing I try to achieve is to learn more about the scene management and frustum culling and picking and many other things which can be done with a scene managed within a tree.
Don´t be bad with my and that stupid decalration I made before, pertaining to the dynamic_cast. I made it out of my non knowledge. But you gave me some hints which surely will be helpfull.
Alex
Quote:
Original post by directNoob
But the polymorthism I just use for multible classes which have the same properties, as I said. Why shouldn´t I use polymorphism?
It´s absolutely suitable. But it is a bit more complex.
My point is that you should take the transform-computing responsibility out of your planet classes and place it in a single Transform class. Since you only need one class to handle transforms, you don't need to use polymorphism (and can't anyway).
I have a matrix class within every object which performs the transformation for the objects. I thought, before rendering, the scene manager should traverse the tree with a function like CalculatePhysics() or CalculateMovement().
So, with the derived classes I have a uniform possibility to fulfill this task, presisely said, the rotation functions or the movement functions.
But you mean, I should have a class which performs that kind of calculs within it instead of within the IObject classes...
For example: That calculation class is going through the tree and performs the movement...
Alex
So, with the derived classes I have a uniform possibility to fulfill this task, presisely said, the rotation functions or the movement functions.
But you mean, I should have a class which performs that kind of calculs within it instead of within the IObject classes...
For example: That calculation class is going through the tree and performs the movement...
Alex
Quote:
Original post by directNoob
I have a matrix class within every object which performs the transformation for the objects. I thought, before rendering, the scene manager should traverse the tree with a function like CalculatePhysics() or CalculateMovement().
The phrase "traverse the tree with X" immediately rings the Visitor Pattern bell in my mind.
Whether or not it applies here, it's something that's good to have in the back of your mind.
Thanks for the link. This really sounds interesting.
And also thanks for your help, all of you. I appreciate this alot, really.
Alex
And also thanks for your help, all of you. I appreciate this alot, really.
Alex
Why is using a type variable bad?
Sure, if you're already using RTTI then it's a waste of time, but sometimes its not advisable to use that. This doc has a section showing the runtime cost of using dynamic_cast and typeid (along with lots of other useful info)
C++ Technical Report on Performance
RTTI itself adds tpye info to your class (including a char array) so I dont see how adding a single int or char to your class can be seen as adding extra memory overhead if RTTI is switched off.
If you have to downcast in speed critical areas then in my mind it would be better to keep a static const int in your base class (or template class derived from pure interface) and use the address comparison to bind to a handler function in which you can use static_cast (in the safe knowledge that only that type will enter that function).
of course, I'm only saying this because I implemented something just like that yesterday at work [grin], maybe I'm completely wrong.
ToohrVyk said there is always a better solution than using a type variable but for my problem I couldnt see a way around using it. I was implementing a messaging system between in game objects and wanted message clients to have a queue for incoming messages, but messages could be of any type so the queue was made up of pointers to the message interface. When the clients would poll their queues, they had to be able to determine the type of the message so that they could downcast it correctly. I initially used RTTI (which is great, hope it gets optimised to hell in the future) but then reverted to the int& trick used in boost after reading the doc linked to above.
I look forward to hearing thoughts on why using a type variable is bad, and any possible alternatives to how I tackled my problem.
cheers,
soddy
*edit* oops, forgot to link that doc properly
Sure, if you're already using RTTI then it's a waste of time, but sometimes its not advisable to use that. This doc has a section showing the runtime cost of using dynamic_cast and typeid (along with lots of other useful info)
C++ Technical Report on Performance
RTTI itself adds tpye info to your class (including a char array) so I dont see how adding a single int or char to your class can be seen as adding extra memory overhead if RTTI is switched off.
If you have to downcast in speed critical areas then in my mind it would be better to keep a static const int in your base class (or template class derived from pure interface) and use the address comparison to bind to a handler function in which you can use static_cast (in the safe knowledge that only that type will enter that function).
of course, I'm only saying this because I implemented something just like that yesterday at work [grin], maybe I'm completely wrong.
ToohrVyk said there is always a better solution than using a type variable but for my problem I couldnt see a way around using it. I was implementing a messaging system between in game objects and wanted message clients to have a queue for incoming messages, but messages could be of any type so the queue was made up of pointers to the message interface. When the clients would poll their queues, they had to be able to determine the type of the message so that they could downcast it correctly. I initially used RTTI (which is great, hope it gets optimised to hell in the future) but then reverted to the int& trick used in boost after reading the doc linked to above.
I look forward to hearing thoughts on why using a type variable is bad, and any possible alternatives to how I tackled my problem.
cheers,
soddy
*edit* oops, forgot to link that doc properly
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement