Hello, C++ Gurus! - returning a derived class enum from the base
by Orion Elenzil · in Torque Game Engine · 07/31/2006 (2:47 pm) · 7 replies
Sooooo
i'd like to make a console method along the lines of "getNextFreeNetMask()",
which would return the value of the common enum "NextFreeMask".
to refresh yr memory, we have for example in gameBase:
i'd really like to only touch SceneObject.h & SceneObject.cc.
which i can't figure out how to do.
so for now i'm adding a virtual getNextFreeMask() in SceneObject which returns 0 (An invalid mask),
and overriding it as needed in Player, ShapeBase, etc.
OR there's the insane method,
adding it into DECLARE_CONOBJECT && IMPLEMENT_CONOBJECT:
the thing i don't like about that is that not all ConObjects are NetObjects,
which means you have to add something like this into consoleObject.h:
the other thing i don't like is that it's bloating an otherwise thin area.
what about templates ?
could i do something like make a global function:
i'd like to make a console method along the lines of "getNextFreeNetMask()",
which would return the value of the common enum "NextFreeMask".
to refresh yr memory, we have for example in gameBase:
enum GameBaseMasks {
InitialUpdateMask = [b]Parent::NextFreeMask[/b],
DataBlockMask = InitialUpdateMask << 1,
ExtendedInfoMask = DataBlockMask << 1,
[b]NextFreeMask[/b] = ExtendedInfoMask << 1
};i'd really like to only touch SceneObject.h & SceneObject.cc.
which i can't figure out how to do.
so for now i'm adding a virtual getNextFreeMask() in SceneObject which returns 0 (An invalid mask),
and overriding it as needed in Player, ShapeBase, etc.
OR there's the insane method,
adding it into DECLARE_CONOBJECT && IMPLEMENT_CONOBJECT:
#define DECLARE_CONOBJECT(className) \
static ConcreteClassRep<className> dynClassRep; \
static AbstractClassRep* getParentStaticClassRep(); \
static AbstractClassRep* getStaticClassRep(); \
virtual AbstractClassRep* getClassRep() const; \
virtual U32 getNextFreeMask(){ return className::NextFreeMask; }the thing i don't like about that is that not all ConObjects are NetObjects,
which means you have to add something like this into consoleObject.h:
enum {
NextFreeMask = 0
};the other thing i don't like is that it's bloating an otherwise thin area.
what about templates ?
could i do something like make a global function:
U32 getNextFreeMask(Template<class>* obj)
{
if (dynamic_cast<sceneObject*> obj)
return <class>::NextFreeMask;
else
return 0;
}About the author
#2
However, I fear that it's the dynamic type that you want to use... Then the bad news is that templates won't help you. Templates are, mainly, to "do things" at compile time, not at runtime. In this case virtual functions are the best way. I would say they're basically the only way. There are in fact other ways, but they are so much more complicated that, frankly, they are not worth the trouble explaining for this very simple case.
07/31/2006 (3:10 pm)
I don't understand what you are trying to achieve. Do you need to retrieve the NextFreeMask of the static type of obj or its dynamic type? Because it makes a hell of a difference. If it's the static type that you want to use, then there's no real need of template, because you can just use that type and append ::NextFreeMask. However, if it's syntactic sugar that you seek, you can use thistemplate <class T>
U32 getNextFreeMask(T* obj)
{
return T::NextFreeMask;
}(notice that if you use it with a ConObject that is not a NetObject you will get a compile-time error.)However, I fear that it's the dynamic type that you want to use... Then the bad news is that templates won't help you. Templates are, mainly, to "do things" at compile time, not at runtime. In this case virtual functions are the best way. I would say they're basically the only way. There are in fact other ways, but they are so much more complicated that, frankly, they are not worth the trouble explaining for this very simple case.
#3
@Tom - cool, thanks for the encouragement. that's what i finally went with.
In the case of objects which don't fool with NextFreeMask themselves, i think it should be fine because it will just drop down to the parent's NextFreeMask, which happens to be correct. yeah ?
@Alberto - NextFreeMask of the static type. My major goal here is actually pretty unimportant. I'm going to be reducing the netmasks of some parent object such as ShapeBase, etc, and would just like an easy way of verifying that indeed the freed-up netmasks are being properly bubbled-up to objects like Player. This could be done by hand, no problem, just sort of tedium if i'm going to be fooling around a lot. In fact, i don't need these numbers at all during runtime, and a compile-time solution would be ideal !
I actually tried the template solution you describe, except consider the usage in a ConsoleMethod:
(pardon my pseudo-code)
.. the templated code will return SceneObject::NextFreeMask,
which is correct for SceneObjects, but not for say Players.
what i'd really like is something like:
however as far as i know that's not possible in C++. It's trivial in say Smalltalk.
obviously i could implement a ConsoleMethod for every single class i have an interest in,
and that would work fine, but it would be a lot of work, prone to error, and an onus when writing new classes.
thanks again.
07/31/2006 (8:11 pm)
Thanks for thinking about this, guys.@Tom - cool, thanks for the encouragement. that's what i finally went with.
In the case of objects which don't fool with NextFreeMask themselves, i think it should be fine because it will just drop down to the parent's NextFreeMask, which happens to be correct. yeah ?
@Alberto - NextFreeMask of the static type. My major goal here is actually pretty unimportant. I'm going to be reducing the netmasks of some parent object such as ShapeBase, etc, and would just like an easy way of verifying that indeed the freed-up netmasks are being properly bubbled-up to objects like Player. This could be done by hand, no problem, just sort of tedium if i'm going to be fooling around a lot. In fact, i don't need these numbers at all during runtime, and a compile-time solution would be ideal !
I actually tried the template solution you describe, except consider the usage in a ConsoleMethod:
(pardon my pseudo-code)
ConsoleMethod of SceneObject :: getTheNextFreeNetMask()
{
// unspoken declaration:
// SceneObject* object;
U32 theAnswer = getNextFreeMask(object); // calling your templated code
}.. the templated code will return SceneObject::NextFreeMask,
which is correct for SceneObjects, but not for say Players.
what i'd really like is something like:
ConsoleMethod of SceneObject :: getTheNextFreeNetMask()
{
// unspoken declaration:
// SceneObject* object;
Class objectClass = classOf(object);
U32 theAnswer = objectClass::NextFreeMask;
}however as far as i know that's not possible in C++. It's trivial in say Smalltalk.
obviously i could implement a ConsoleMethod for every single class i have an interest in,
and that would work fine, but it would be a lot of work, prone to error, and an onus when writing new classes.
thanks again.
#4
What I meant was that some classes declare some additional mask bits but not NextFreeMask. In one case I noticed in TSE back around GDC time, NextFreeMask was defined but set incorrectly ... although I mentioned that to Brian and I think it got fixed ages ago. In any case, I believe it was on water and unlikely ever to be an issue in normal usage.
For those objects, you'd get the parent's NextFreeMask and depending on how you are using it, that could cause problems.
T.
Edit: Just read what you said to Alberto. Yeh, if my above assertions are accurate, then you'd end up with some bit counts being incorrect.
07/31/2006 (9:08 pm)
@Orion,Quote:In the case of objects which don't fool with NextFreeMask themselves, i think it should be fine because it will just drop down to the parent's NextFreeMask, which happens to be correct. yeah ?
What I meant was that some classes declare some additional mask bits but not NextFreeMask. In one case I noticed in TSE back around GDC time, NextFreeMask was defined but set incorrectly ... although I mentioned that to Brian and I think it got fixed ages ago. In any case, I believe it was on water and unlikely ever to be an issue in normal usage.
For those objects, you'd get the parent's NextFreeMask and depending on how you are using it, that could cause problems.
T.
Edit: Just read what you said to Alberto. Yeh, if my above assertions are accurate, then you'd end up with some bit counts being incorrect.
#5
08/02/2006 (10:16 am)
Quote:There must be a misunderstanding about what is the static and what is the dynamic type. I refer to the definitions of C++ standard and from your remarks it's now clear to me that what you need is the dynamic type and not the static type. In fact, in your example the static type is always SceneObject whatever object is being passed, while the dynamic is the "actual" type of the object (i.e.: Player, Item, etc.). The getClassObject function is in fact an accessor that returns the dynamic type of the given object.
.. the templated code will return SceneObject::NextFreeMask,
which is correct for SceneObjects, but not for say Players.
#6
Yes, what i want is exactly the dynamic class !
A quick search on getClassObject() suggests that using it would involve bringing in a whole bunch of things which aren't currently in the TGE codebase. eg, COM, ATL, etc. Is this the case ? will getClassObject() compile under linux GCC, for example ?
cheers,
orion
08/02/2006 (11:10 am)
Hi Alberto - thanks for the reply.Yes, what i want is exactly the dynamic class !
A quick search on getClassObject() suggests that using it would involve bringing in a whole bunch of things which aren't currently in the TGE codebase. eg, COM, ATL, etc. Is this the case ? will getClassObject() compile under linux GCC, for example ?
cheers,
orion
#7
08/03/2006 (1:44 am)
Ah! You were talking of that getClassObject()... I blindly thought there was some function in Torque with that name... I confirm that getClassObject() won't compile under Linux, but you have a much better replacement and it's the C++ standard typeid() operator, which doesn't have strange dependencies and is guaranteed to work on Linux too. However, if you use it you are going into the area of the "other ways" that I mentioned in a previous post of mine and that are "not worth the trouble explaining" because your original approach is simpler and probably better ;)
Torque 3D Owner Tom Bampton
It's not that insane a solution, really. I've abused the console in much more insane ways in the past ;-)