Sign in to follow this  

typeid not working

This topic is 4109 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

G'day I need to check if my pointer my base class is actually a pointer to a particular child class: ie My Class hierarchary looks like this: ParentClass // base class ChildClass GrandChild Class // the class im checking for, also inherients from another class GreatGrandChild class my code looks like this
ParentClass* blah = *instanceIterator // blah comes from a list
if (typeid(blah) == typeid(Grandchild*)) // this should return true, since blah is a Grandchild class.
By my understanding typeid should work. I dont think it would make a difference but, GrandChild inherients from ChildClass and another class. Any ideas on what i'm doing wrong ?

Share this post


Link to post
Share on other sites
blah is a local pointer variable of type ParentClass*, so your code will always return false. Although it is of type ParentClass*, it happens to point at a polymorphic object of type GrandChildClass. This is the type you want to check (the type of the object, not the type of the pointer):

if (typeid(*blah) == typeid(GrandChildClass))

Share this post


Link to post
Share on other sites
Quote:
Original post by f001error
Any ideas on what i'm doing wrong ?

What you're doing wrong is (almost certainly) requiring a type-check to switch behaviour (type-switching, evil, brittle, error-prone) instead of using virtual functions.

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
blah is a local pointer variable of type ParentClass*, so your code will always return false. Although it is of type ParentClass*, it happens to point at a polymorphic object of type GrandChildClass. This is the type you want to check (the type of the object, not the type of the pointer):

if (typeid(*blah) == typeid(GrandChildClass))


Nope, still returning false :(


Quote:

What you're doing wrong is (almost certainly) requiring a type-check to switch behaviour (type-switching, evil, brittle, error-prone) instead of using virtual functions.

Σnigma


I can't use virtual functions for this. I've got a list of entites that are currently on screen, I'm iterating through that list, checking if the mouse is inside the entity. If it is, I then check to see if its a button subclass of entity. If it is a button I then fire off some code to handle the mouseover.

Share this post


Link to post
Share on other sites
Quote:
Original post by f001error
I can't use virtual functions for this. I've got a list of entites that are currently on screen, I'm iterating through that list, checking if the mouse is inside the entity. If it is, I then check to see if its a button subclass of entity. If it is a button I then fire off some code to handle the mouseover.


?


class BaseClass {
virtual OnMouseOver() = 0;
}
std::list<BaseClass*> objectsOnScreen;
for_each objectsOnScreen o {
o->OnMouseOver();
}


That said, I don't know why typeid isn't working, I've never used RTTI.

Share this post


Link to post
Share on other sites
If you really want to do this (which is a bad idea most of the time), then you can instead use dynamic_cast:


ScreenEntity * myScreenEntity = ...;
Button * b = dynamic_cast<Button *>(myScreenEntity);
if (b != 0) {
b->DoButtonStuff(where);
return;
}


However, if you have a list of screen entities, it makes more sense to build dispatching into the base class ScreenEntity. Being able to tell the engine whether you want a click or not is naturally part of being a screen entity.


class ScreenEntity {
public:
virtual bool ProcessMouseEvent(Point where) = 0;
};


so your code just becomes:


ScreenEntity * myScreenEntity = ...;
if (myScreenEntity->ProcessMouseEvent(where)) {
return;
}

Share this post


Link to post
Share on other sites
An alternative to hplus0603's suggestion is to maintain two lists. One which contains all entities and another which contains only "mouseoverables", i.e.:
#include <algorithm>
#include <deque>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_deque.hpp>

class UserInterface;

class Entity
{

public:

virtual ~Entity(){}
virtual void render() = 0;

protected:

Entity(UserInterface & user_interface);

};

struct MouseCoordinates
{
unsigned short x;
unsigned short y;
};

class Mouseoverable
:
public virtual Entity
{

public:

virtual void on_mouse_over(MouseCoordinates coordinates) = 0;

protected:

Mouseoverable(UserInterface & user_interface);

};

class Label
:
public Entity
{

public:

static void create(UserInterface & user_interface);
virtual void render();

private:

Label(UserInterface & user_interface);

};

class Button
:
public Mouseoverable
{

public:

static void create(UserInterface & user_interface);
virtual void on_mouse_over(MouseCoordinates coordinates);
virtual void render();

private:

Button(UserInterface & user_interface);

};

class UserInterface
{

public:

void add(Entity & entity);
void add(Mouseoverable & mouseoverable);
void mouse_move(MouseCoordinates coordinates);
void render();

private:

boost::ptr_deque< Entity > entities_;
std::deque< Mouseoverable * > mouseoverables_;

};

Entity::Entity(UserInterface & user_interface)
{
user_interface.add(*this);
}

Mouseoverable::Mouseoverable(UserInterface & user_interface)
:
Entity(user_interface)
{
user_interface.add(*this);
}

void Label::create(UserInterface & user_interface)
{
new Label(user_interface);
}

void Label::render()
{
// render label;
std::cout << "rendering label\n";
}

Label::Label(UserInterface & user_interface)
:
Entity(user_interface)
{
}

void Button::create(UserInterface & user_interface)
{
new Button(user_interface);
}

void Button::on_mouse_over(MouseCoordinates /*coordinates*/)
{
// do stuff
std::cout << "mouse over button\n";
}

void Button::render()
{
// render button
std::cout << "rendering button\n";
}

Button::Button(UserInterface & user_interface)
:
Mouseoverable(user_interface)
{
}

void UserInterface::add(Entity & entity)
{
entities_.push_back(&entity);
}

void UserInterface::add(Mouseoverable & mouseoverable)
{
mouseoverables_.push_back(&mouseoverable);
}

void UserInterface::mouse_move(MouseCoordinates coordinates)
{
std::for_each(mouseoverables_.begin(), mouseoverables_.end(), boost::bind(&Mouseoverable::on_mouse_over, _1, coordinates));
}

void UserInterface::render()
{
std::for_each(entities_.begin(), entities_.end(), boost::bind(&Entity::render, _1));
}

int main()
{
UserInterface user_interface;
Label::create(user_interface);
Button::create(user_interface);
user_interface.render();
MouseCoordinates mouse_coordinates = {320, 200};
user_interface.mouse_move(mouse_coordinates);
}



This is just an example I threw together. There may be design issues I haven't noticed. If so I'm sure Zahlman or someone else will point them out.

EDIT: added virtual inheritance to avoid one potential design issue.
EDIT2: and virtual destructor (oops!)

Σnigma

[Edited by - Enigma on September 17, 2006 6:06:24 AM]

Share this post


Link to post
Share on other sites
To take it a step further, I don't see why you have two separate kinds of entities anyway. From an OO point of view there is little correlation between 'Entity' (which I assume is something that 'lives' in your world) and a mouseover event (which belongs to the UI). I would rather see it like this: some entities are represented by a screen image that can be clicked. So it might be better to give all entities an 'clickable image' member, which can be used or not. Then all entities will become obedient little commies again and your problem non-existant.

Share this post


Link to post
Share on other sites
I'm much too tired right now to look at Enigma's code, but I'll just fill in the philosophy here: if you're putting things of an inheritance hierarchy into a container, it's should be because you want to do the same basic things with each of them, and let the things be responsible for any different effects. "I have some Parents, and I want them all to doWonderfulThings()" - children do wonderful things *differently*, but they do the same things as their parents. So any time you care explicitly about the (exact) type of something you pull out of a container, it points to a confused design: the reason for putting the things into the container was to *forget* details of exact type that aren't relevant.

Share this post


Link to post
Share on other sites
The actual solution to your problem:
typeid(*blah) == typeid(Grandchild) is true if and only if blah is a pointer to an instance of Grandchild. It is not true if blah is a pointer to an instance of a class derived from Grandchild.

To get something that evaluates true for derived classes of Grandchild you should use: dynamic_cast<Grandchild*>(blah)

However, as many other people have pointed out, your current design is a bit flaky. You really should use a virtual onMouseOver() function that does nothing by default. Think about how much effort it would be if you need a type of entity that responds when the mouse is moved over it but isn't a button.

Share this post


Link to post
Share on other sites

This topic is 4109 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this