Keeping Track Of Classes

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Sliver
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 8
Joined: Sat Jun 06, 2009 4:27 pm

Keeping Track Of Classes

Post by Sliver »

This isn't really a question - just want to see how other people do this.

If you've got a base class object, with other classes derived from it, what's the best way to store and keep track of each class?

I just have a few vectors and some accessor functions:

Code: Select all

vector<object*> objects;
vector<character*> characters;
vector<item*> items;

int GetObjectCount();
int GetItemCount();
int GetCharacterCount();

object* GetObjectByIndex(int id);
item* GetObjectByIndex(int id);
character* GetCharacterByIndex(int id);

//more functions like delete etc
I'm sure there's a better way of doing it than this. Any ideas?
All programmers are playwrights and all computers are lousy actors.
User avatar
programmerinprogress
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 632
Joined: Wed Oct 29, 2008 7:31 am
Current Project: some crazy stuff, i'll tell soon :-)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++!
Location: The UK
Contact:

Re: Keeping Track Of Classes

Post by programmerinprogress »

In my current project i'm implementing polymorhism, which allows me to store a bunch of pointers (of the derived objects) into the same container, because the pointers being used are of the Base type.

with this, you can do more than just store the pointers more efficiently, you can actually amalglamate all of the methods in the parent class that currently contain the seperate methods for each object, so rather than 'getting' an object and 'getting' a character, you simply return a pointer of the base type so that you don't need to redo a new function each time you come up with a new type of derived object.

hopefully, you'll get to a point where you will be implementing new objects, derived from the base class, without having to alter any of the code contained in the parent class which contains and controls all of the data, in a sense you'll end up encapsulating the data further, and it will even allow you to write new objects without any prior knowledge of the class that controls them (all you need to know are the declarations of the methods in the class you are deriving from, that way you can make a standard interface which all objects can use, and the controlling class can interpret without you having to change what's in the controlling class)

I hope this wasn't complete nonsense, but i'm using polymorphism in my current project, to allow my main program to be expanded easily, without changing the parent classes code.
---------------------------------------------------------------------------------------
I think I can program pretty well, it's my compiler that needs convincing!
---------------------------------------------------------------------------------------
And now a joke to lighten to mood :D

I wander what programming language anakin skywalker used to program C3-PO's AI back on tatooine? my guess is Jawa :P
Sliver
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 8
Joined: Sat Jun 06, 2009 4:27 pm

Re: Keeping Track Of Classes

Post by Sliver »

programmerinprogress wrote:In my current project i'm implementing polymorhism, which allows me to store a bunch of pointers (of the derived objects) into the same container, because the pointers being used are of the Base type.
Yeah, I sware by polymorphism too, but what if you need to use a method from one of the specialised classes? Does a C cast return the entire object?

For example(item is derived from object):

Code: Select all

item* GetItemByIndex(int id)
{
//would this keep the item specific member variables intact?
return (item*)Objects[id];

//or is it better to keep a seperate list of items?
return Items[id];
}
Thanks.

EDIT: Sorry for being lazy, I can answer the question myself with this:

Code: Select all

#include <iostream>
class A
{
public:
	A(){}
	~A(){}
};

class B: public A
{
public:
	int s;
	B(){}
	~B(){}
};

A* as[3];

int main()
{
//create a derived object
 B* b = new B();
 b->s = 8;

 //store the object in an array of the base class:
 as[0] = b;

 //print a specific variable
B* z = (B*)as[0];
std::cout << z->s;
system("pause");
}
Run that program and it works - it prints "8" to the screen. :) Next challenge is to distinguish between classes. Perhaps a constant enum identifier variable?
All programmers are playwrights and all computers are lousy actors.
User avatar
programmerinprogress
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 632
Joined: Wed Oct 29, 2008 7:31 am
Current Project: some crazy stuff, i'll tell soon :-)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++!
Location: The UK
Contact:

Re: Keeping Track Of Classes

Post by programmerinprogress »

yeah, I do an explicit cast on the object like so

Code: Select all

cDerived* newbutton = (cDerived*)GetControl("DERIVED_ONE"); 
// explicit cast seems to do the job for me anyway 
newbutton->soDerivedStuff();

// the method's declaration is as follows 
cBase* GetControl(string tag);

This seems to be working fine for me, remember that you're returning a reference to an object, you wont magically lose parts of the object if you do a simple base to derived cast, as far as I know anyway.
---------------------------------------------------------------------------------------
I think I can program pretty well, it's my compiler that needs convincing!
---------------------------------------------------------------------------------------
And now a joke to lighten to mood :D

I wander what programming language anakin skywalker used to program C3-PO's AI back on tatooine? my guess is Jawa :P
wacko
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 12
Joined: Sat Oct 25, 2008 1:36 am

Re: Keeping Track Of Classes

Post by wacko »

Sliver wrote:Run that program and it works - it prints "8" to the screen. :) Next challenge is to distinguish between classes. Perhaps a constant enum identifier variable?
So there is a couple ways to solve this issue one way which I think works alright is...

Code: Select all

enum ObjectType {
  e_objectUnknown = -1,
  e_objectFoo,
  e_objectBar,  
};

class A {
  virtual ObjectType GetType() { return e_objectUnknown; }
};

class B : public A {
  ObjectType GetType () { return e_objectFoo; }
};

B* GetFoo(unsigned int index) {
  if (index >= arrayLength) {
    return NULL;
  }
  
  if (array[index] != NULL &&
      array[index]->GetType() != e_objectFoo) {
    return NULL;
  }
  
  return static_cast<B*>(array[index]);
}
there is some stuff left out but it should give you the main idea... and personally I do not like C-style casts they just are hard to understand sometimes or see, they can cause much pain and the compiler will not always catch that pain.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Keeping Track Of Classes

Post by Falco Girgis »

Silver wrote: Run that program and it works - it prints "8" to the screen. :) Next challenge is to distinguish between classes. Perhaps a constant enum identifier variable?
That's the entire point of RTTI. Google how to enable it on your compiler of choice.
wacko
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 12
Joined: Sat Oct 25, 2008 1:36 am

Re: Keeping Track Of Classes

Post by wacko »

So I think RTTI should only be used when needed, there was a reason why it was not in the lang to begin with and thats because people use it incorrectly. I think the solution I provided above works and does allow for any of the RTTI badness to happen. Also if they really wanted to they could hold each derived type in a specific container to that type and not loose the type information at all. But generally RTTI should be avoided if there is a better alt.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Keeping Track Of Classes

Post by Falco Girgis »

Yes, RTTI comes with a performance drop. But it's also extremely convenient.

I would never consider using it for a real-time application with limited RAM, but if he's doing this for something like a level editor, or some sort of development tool that is going to be run on a PC, I think he should go for it. On today's machines, the cost of RTTI is close to nothing.

The only performance hit of RTTI comes from additional space needed by the type_info. Your run-time performance is not affected (except for when you're checking for types, of course).
wacko
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 12
Joined: Sat Oct 25, 2008 1:36 am

Re: Keeping Track Of Classes

Post by wacko »

I think if you can avoid using the dynamic_cast then you should do so, I mean if you can either keep the info around in a sep container and not lose any type info or add the virtual function if it makes sense then do so. I would only use the dynamic_cast when its really needed. the project I am currently working on has well over a million lines of code and the amount of times i needed to use RTTI is than 10. Its just not needed there are so many more ways you could write your code that allows what you want and gives a clean nice interface that gives proper compiler errors when needed. I think what your advocating is a poor programming practice and leads to buggy code and many hours wasted hunting down a poorly used dynamic_cast
internetfx
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 11
Joined: Mon Sep 28, 2009 1:11 am

Re: Keeping Track Of Classes

Post by internetfx »

wacko wrote:I think if you can avoid using the dynamic_cast then you should do so, I mean if you can either keep the info around in a sep container and not lose any type info or add the virtual function if it makes sense then do so. I would only use the dynamic_cast when its really needed. the project I am currently working on has well over a million lines of code and the amount of times i needed to use RTTI is than 10. Its just not needed there are so many more ways you could write your code that allows what you want and gives a clean nice interface that gives proper compiler errors when needed. I think what your advocating is a poor programming practice and leads to buggy code and many hours wasted hunting down a poorly used dynamic_cast
No, no. Your code segment is basically dynamic_cast<T*>, so you're not doing anything different than RTTI -- except that RTTI requires no extra code. How exactly is RTTI bad programming practice if your method directly emulates it?

dynamic_cast<T> is clean: it throws an exception on a mismatch (unlike static_cast<>) so you can put it in a try block and catch it.

dynamic_cast<T*> returns a NULL on a mismatch, which is exactly what you're doing.

And I must submit that dynamic_cast<> is going to be a little faster than programming the checks yourself.

That's not to say that it's pointless to have derived classes identify themselves, and your example illustrates a good way to do this. Your identity functions will be laid out in the virtual table and type information will be invisibly stored with each object.
wacko
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 12
Joined: Sat Oct 25, 2008 1:36 am

Re: Keeping Track Of Classes

Post by wacko »

I do not know where you got your info on the cost of dynamic_cast but its costly. The code i wrote above is 20x faster if you just use the GetType functionality of the virtual call than using dynamic_cast. It has to walk the entire class hierarchy, which includes dealing with crap like virtual tables, multiple inheritance, possible ambiguities in base objects and its even worse on 64bit systems. to do a dynamic_cast is an O(n) operation when it comes to inheritance hierarchy, which is not the case for the virtual function. Sure in some cases where its a very special one off case I could see using dynamic_cast/RTTI but if correctly architected you should not need to do anything like that and in this posters case I think the best option is something like the one I posted above.
internetfx
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 11
Joined: Mon Sep 28, 2009 1:11 am

Re: Keeping Track Of Classes

Post by internetfx »

wacko wrote:I do not know where you got your info on the cost of dynamic_cast but its costly. The code i wrote above is 20x faster if you just use the GetType functionality of the virtual call than using dynamic_cast. It has to walk the entire class hierarchy, which includes dealing with crap like virtual tables, multiple inheritance, possible ambiguities in base objects and its even worse on 64bit systems. to do a dynamic_cast is an O(n) operation when it comes to inheritance hierarchy, which is not the case for the virtual function. Sure in some cases where its a very special one off case I could see using dynamic_cast/RTTI but if correctly architected you should not need to do anything like that and in this posters case I think the best option is something like the one I posted above.
So now we're talking about performance, instead of you saying that using dynamic_cast<> is poor programming practice and leads to buggy code. Wait, where was that? Oh yeah:
wacko wrote:I think what your advocating is a poor programming practice and leads to buggy code [...]
Also:
wacko wrote:[...] there was a reason why it was not in the lang to begin with and thats because people use it incorrectly.
Explain: how did people use it incorrectly if it wasn't in the language? I digress.

Okay, so performance it is.

Are we talking about an ambiguous multi-level heirarchy, then? 20 times faster seems a bit of a reach, say, for one heirarchy level. Is this comparison in an unoptimized compile? Certainly dynamic_cast<> is capable of tens of millions of these per second. It would be a fun exercise to test this on a couple of compilers, maybe gcc and Visual.

If there are more levels of heirarchy to walk through, it does become a big deal. I'm wondering about the context of the test, though.

I don't know if you would do a lot of cast tests in the context of most games, and I mean per frame. It seems you would aim to segment your different objects to gain more natural optimization benefits and avoid the casts for the most part. Usually cast tests happen in a collision or some special event that one object needs to know the type, as well as the identity, of the event objects. On the other hand, if you had to go through a thousand dynamic_cast<> operations every frame, you might see a couple of milliseconds wasted, and yes, that could be a serious expenditure.

I wouldn't be so concerned with dynamic_cast<> performance until you have a little bit of volume, but that's true about any optimization. I wouldn't put in extra code if RTTI can handle it in small volume.

In any event, Mr. Stroustrup would be so unhappy if he found out his operator was advocating bad programming practice!
User avatar
MarauderIIC
Respected Programmer
Respected Programmer
Posts: 3406
Joined: Sat Jul 10, 2004 3:05 pm
Location: Maryland, USA

Re: Keeping Track Of Classes

Post by MarauderIIC »

I hadn't really paid much attention to dynamic_cast<>, but 30 seconds of research gives me pretty consistent results.
internetfx wrote:Are we talking about an ambiguous multi-level heirarchy, then? 20 times faster seems a bit of a reach, say, for one heirarchy level. Is this comparison in an unoptimized compile? Certainly dynamic_cast<> is capable of tens of millions of these per second. It would be a fun exercise to test this on a couple of compilers, maybe gcc and Visual.
http://forum.openscenegraph.org/viewtopic.php?t=652
Conclusions:
- For my config (see below), benchmark says that using a virtual call if *FAR* cheaper (roughly 10-20 times!).
- The virtual call test uses a string comparison that is of course affected by the length of the string, but that's even not noticeable in release.
(Emphasis mine)

http://forum.openscenegraph.org/viewtop ... =2676#2676
However when doing a dynamic_cast you probably don't want to check for exact type (which is what the name compare is doing) but rather find out if an object supports a certain interface i.e. is derived from a specific base class. You simply can't do that by checking the class name
http://forum.openscenegraph.org/viewtop ... =2681#2681
Well of course a dynamic_cast is not always repleacable by a className() call. This happens only sometimes. My bench' only says "if you can, then use className()" and also says "use dynamic_cast wisely: it costs a lot".
http://www.informit.com/guides/content. ... seqNum=179
As a rule, don't delay any type checking that can take place at compile to runtime. Early type checking ensures faster execution time, smaller executable files and most importantly: early error detection. However, there are cases in which the use of dynamic type checking is inevitable. In those cases, operator dynamic_cast is a useful tool.
http://www.devx.com/tips/Tip/5496
An invocation of operator typeid is a constant time operation--it takes the same length of time to retrieve the runtime type information of every polymorphic object, regardless of the object's derivational complexity. On the other hand, dynamic_cast<> is not a constant time operation. It has to traverse the derivation tree of the operand until it has located the target object in it. The worst case scenario is when the operand is a deeply derived object and the target is a non-related class type. Then, dynamic_cast<> has to traverse the entire derivation tree before it can confidently decide that requested cast cannot be done.
http://www.velocityreviews.com/forums/s ... ostcount=3
Sorry for the code. I'll do my best next time.
In the meantime here are some results:

CALLING ITERATIONS 50000000

static_cast version
Result 150000000
Computation time (sec)2
Computation time (msec)1530000

dynamic_cast version
Result 150000000
Computation time (sec)24
Computation time (msec)22000000
Code @ http://www.velocityreviews.com/forums/s ... ostcount=1
internetfx wrote:If there are more levels of heirarchy to walk through, it does become a big deal. I'm wondering about the context of the test, though.
"Roughly 10-20x"
http://forum.openscenegraph.org/viewtopic.php?t=652

Code: Select all

osg::Node * p = new osg::MatrixTransform;
assert(strcmp(p->className(), "MatrixTransform")==0);
clock_t start = ::clock();
for(int i=0; i<10000000; ++i) {
    if (dynamic_cast<osg::MatrixTransform*>(p)) {
        int i=0;
    }
}
std::cout << ::clock()-start << std::endl;
start = ::clock();
for(int i=0; i<10000000; ++i) {
    if (strcmp(p->className(), "MatrixTransform")==0) {
        int i=0;
    }
}
std::cout << ::clock()-start << std::endl; 
So if you can cast it at compile time, you should. If you want to see if a certain function is supported, use dynamic_cast. If you want to see if it's of a certain type and perform operations on it, use a compile-time cast. At least, that's the impressions I get.
I realized the moment I fell into the fissure that the book would not be destroyed as I had planned.
internetfx
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 11
Joined: Mon Sep 28, 2009 1:11 am

Re: Keeping Track Of Classes

Post by internetfx »

Seems pretty consistent with what I said, although the tests suggested don't depict a single-level hierarchy (but I wouldn't discount it). One of the tests you illustrated was actually a speed comparison between dynamic_cast<> and static_cast<> for pointer passing where no testing was done, which is not what we're talking about. Note that it only took 12 times as long to do a dynamic_cast<> than a practically free static_cast<> with no test.

10x the time still seems oddly large. I would expect it could get this high, or much higher with a deeply derived class.

In the order of several million dynamic_cast<> operations per second, it's only a question on whether it's worth replacing. There's never an excuse to use it wastefully, but I wonder in what scenarios one would be afraid of dynamic_cast<>, even in high-performance games, without other optimizations nullifying the need for it. My argument is that it is not poor programming practice and it probably isn't something to avoid until its performance becomes a factor.

Thanks immensely for your input; those were good reads!
User avatar
MarauderIIC
Respected Programmer
Respected Programmer
Posts: 3406
Joined: Sat Jul 10, 2004 3:05 pm
Location: Maryland, USA

Re: Keeping Track Of Classes

Post by MarauderIIC »

internetfx wrote:Seems pretty consistent with what I said, although the tests suggested don't depict a single-level hierarchy (but I wouldn't discount it). ... I would expect it could get this high, or much higher with a deeply derived class.
dynamic_casting something to its own type would seem the fastest thing in general, and it's still 10x slower. Perhaps I'm misunderstanding what you mean when you say "single-level hierarchy". You mean a class that's not derived from anything else being cast to itself? I would have thought that dynamic_cast would start at the bottom and traverse the inheritance tree upwards.

Code: Select all

osg::Node * p = new osg::MatrixTransform;...
    if (dynamic_cast<osg::MatrixTransform*>(p)) {
I realized the moment I fell into the fissure that the book would not be destroyed as I had planned.
Post Reply