Reputation: 24866
Imagine I have such class hierarchy:
Base
A : Base
B : Base
C : B
I want to be able to retrive a string
type from Base
object (I need string, not enum)
. I want also to be able to compare object type to A
type for example:
Object *object = new A();
if (object->type() == A::typename())
{
//hooray!
}
For now I'm planing to add a static function to each class:
static string typename() {return "Different name for each class";}
and then I will have to reimplement Base
function virtual string type()
for every derived class:
A: virtual string type() {return typename();} //A::typename
B: virtual string type() {return typename();} //B::typename
...
I think such design looks ugly. Is there some better way to achieve my goal?
Why I need this: I'm developing a game. There is a tile map. Each tile has an array of objects on it. Some objects can be placed over the others. So i want to check if it is allow to put the object at the specific tile. For example: if tile has object with type "pot" then the flower can be put there.
Upvotes: 0
Views: 143
Reputation: 163
I was searching for a comfortable way of doing this for days. Here's how I did it finally. The solution is pragmatic, compiles fast and is portable and works without RTTI. However it uses #define, which C++ folks try to avoid often. Maybe someone can turn that code into one that uses templates, which I would also be interested in.
Basically, the pointer to a static method is used for comparison with the one returned by "other" object in "static bool IsTypeOf(_TypeCheckBase& other)" so as to provide a type-check. In addition you can get the name of the object.
#define TYPE_CHECK_IMPL(T) \
static bool IsTypeOf(_TypeCheckBase& other) { \
return other.GetType() == (unsigned int)&IsTypeOf; } \
virtual unsigned int GetType() { \
return (unsigned int)&IsTypeOf; } \
public: virtual const string& GetTypeName() { \
static string typeName = #T; \
return typeName; }
#define TYPE_CHECK_DECL(T) \
typedef T _TypeCheckBase;\
TYPE_CHECK_IMPL(T)
class root
{
public:
TYPE_CHECK_DECL(root)
};
class A: public root
{
public:
TYPE_CHECK_IMPL(A)
};
class AA: public A
{
public:
TYPE_CHECK_IMPL(AA)
};
class B: public root
{
public:
TYPE_CHECK_IMPL(B)
};
No you can do the following:
inline void prn(std::string txt, bool val)
{
cout << txt << ": " << (val ? "true":"false") << endl;
}
#define CMP(foo,bar) prn(#foo "\tis type of " #bar " TypeName:\"" + bar.GetTypeName() + "\"", foo::IsTypeOf(bar));
int main(void)
{
A a; AA aa;
B b;
cout << endl;
CMP(A,a);
CMP(AA,a);
CMP(B,a);
CMP(A,aa);
CMP(AA,(*((A*)&aa)));
CMP(B,aa);
CMP(A,b);
CMP(AA,b);
CMP(B,b);
}
The main methods you use here are:
bool Foo::IsTypeOf(bar) with Foo being a class type and bar being an object, derived directly or indirectly from your root class type.
string bar.GetTypeName()
Upvotes: 0
Reputation: 258678
You can achieve the same thing with dynamic_cast
. Your classes are polymorphic anyway.
Note that this is at least a code smell. You shouldn't need to find the actual type of classes in a well-thought design. What underlying problem are you trying to solve?
Also, typename
is a keyword in C++, you should name your method differently.
EDIT: A possible better solution for this would be to have a list of pairs of objects that can be stacked, and have virtual methods:
class Object
{
virtual bool canStack(const std::string& baseObject) = 0;
};
class Flower
{
virtual bool canStack(const std::string& baseObject)
{
if ( baseObject == "pot" )
return true;
return false;
}
};
Now I see why you'd want the get name.
Upvotes: 3