S
Stuart Golodetz
Hi,
I've got a minor casting issue which I need to check about (marked // <--).
I was trying to do a static_cast on it (which didn't work, though I'm not
sure why this should be the case?) I also tried reinterpret_cast (which is
clearly an exceedingly dodgy thing to do; it worked, but I'm not sure
whether it should have worked, or whether (the more likely scenario) it was
just coincidence?) Finally, after a bit of trawling through the FAQ, I
found:
"[25.13] What special considerations do I need to know about when I use a
class that uses virtual inheritance?
No C-style downcasts; use dynamic_cast instead.
(Rest to be written.)"
Having read that, I think the actual solution to the problem is fairly clear
(use dynamic_cast), but I'm curious to know why it's necessary there (and
whether reinterpret_cast would actually work). This is probably going to be
an example of premature optimization, but this is a (clearly very basic)
testbed for an events subsystem in my engine, and I'm expecting there to be
lots of events around at once, hence if the (albeit slight) overhead of
dynamic_cast could be avoided by using reinterpret_cast (the loss of a
safety net is not that much of an issue here), that would be preferable.
Obviously, if dynamic_cast is the only (defined ) way to go, so be it.
#include <iostream>
class EventBase
{
protected:
int m_flags;
public:
enum // event flags
{
EF_AUDIBLE = 1,
EF_VISIBLE = 2
};
EventBase()
: m_flags(0)
{}
virtual ~EventBase() {}
int flags() const
{
return m_flags;
}
};
class EventAudible : virtual public EventBase
{
public:
EventAudible()
{
m_flags |= EF_AUDIBLE;
}
void do_audible_thing()
{
std::cout << "audible thing\n";
}
};
class EventVisible : virtual public EventBase
{
public:
EventVisible()
{
m_flags |= EF_VISIBLE;
}
void do_visible_thing()
{
std::cout << "visible thing\n";
}
};
class EventPlayerFiresWeapon : public EventAudible, public EventVisible
{
};
int main()
{
EventBase *pBase = new EventPlayerFiresWeapon;
int flags = pBase->flags();
std::cout << flags << '\n';
if(flags & EventBase::EF_AUDIBLE)
{
EventAudible *p = dynamic_cast<EventAudible*>(pBase); // <--
p->do_audible_thing();
}
//...
delete pBase;
return 0;
}
TIA,
Stuart.
P.S. I welcome any and all comments on the design itself - if it's bad, I'd
rather know now
P.P.S. There are a couple of obvious placeholder functions in the above
design; in the actual thing, there would instead be things like:
class EventAudible
{
//...
virtual int magnitude() const; // used by the event manager to
determine the radius of sphere within which the sound is audible, in order
to notify nearby entities
//...
};
In other words, the above cast will be necessary in the final design as it
stands at the moment.
I've got a minor casting issue which I need to check about (marked // <--).
I was trying to do a static_cast on it (which didn't work, though I'm not
sure why this should be the case?) I also tried reinterpret_cast (which is
clearly an exceedingly dodgy thing to do; it worked, but I'm not sure
whether it should have worked, or whether (the more likely scenario) it was
just coincidence?) Finally, after a bit of trawling through the FAQ, I
found:
"[25.13] What special considerations do I need to know about when I use a
class that uses virtual inheritance?
No C-style downcasts; use dynamic_cast instead.
(Rest to be written.)"
Having read that, I think the actual solution to the problem is fairly clear
(use dynamic_cast), but I'm curious to know why it's necessary there (and
whether reinterpret_cast would actually work). This is probably going to be
an example of premature optimization, but this is a (clearly very basic)
testbed for an events subsystem in my engine, and I'm expecting there to be
lots of events around at once, hence if the (albeit slight) overhead of
dynamic_cast could be avoided by using reinterpret_cast (the loss of a
safety net is not that much of an issue here), that would be preferable.
Obviously, if dynamic_cast is the only (defined ) way to go, so be it.
#include <iostream>
class EventBase
{
protected:
int m_flags;
public:
enum // event flags
{
EF_AUDIBLE = 1,
EF_VISIBLE = 2
};
EventBase()
: m_flags(0)
{}
virtual ~EventBase() {}
int flags() const
{
return m_flags;
}
};
class EventAudible : virtual public EventBase
{
public:
EventAudible()
{
m_flags |= EF_AUDIBLE;
}
void do_audible_thing()
{
std::cout << "audible thing\n";
}
};
class EventVisible : virtual public EventBase
{
public:
EventVisible()
{
m_flags |= EF_VISIBLE;
}
void do_visible_thing()
{
std::cout << "visible thing\n";
}
};
class EventPlayerFiresWeapon : public EventAudible, public EventVisible
{
};
int main()
{
EventBase *pBase = new EventPlayerFiresWeapon;
int flags = pBase->flags();
std::cout << flags << '\n';
if(flags & EventBase::EF_AUDIBLE)
{
EventAudible *p = dynamic_cast<EventAudible*>(pBase); // <--
p->do_audible_thing();
}
//...
delete pBase;
return 0;
}
TIA,
Stuart.
P.S. I welcome any and all comments on the design itself - if it's bad, I'd
rather know now
P.P.S. There are a couple of obvious placeholder functions in the above
design; in the actual thing, there would instead be things like:
class EventAudible
{
//...
virtual int magnitude() const; // used by the event manager to
determine the radius of sphere within which the sound is audible, in order
to notify nearby entities
//...
};
In other words, the above cast will be necessary in the final design as it
stands at the moment.