Casting function parameter from Base* to Derived*

R

Raider

I have simple class hierarchy (without multiple inheritance):
class Base {};
class Derived : public Base {};
class DeepDerived : public Derived {};
// ... a lot of types

Is it ok to cast void(Base*) to void(Derived*) if I know exactly what I
will pass Derived* as a parameter?

I want to register different handlers for different types using
std::map:
typedef void Handler(Base*);
std::map<const std::type_info*, Handler*> Handlers;

Imagine code like this:
void DerivedHandler(Derived*);
Handlers[&typeid(Derived)] =
reinterpret_cast<Handler*>(&DerivedHandler);
Base* P = ...;
std::map<const std::type_info*, Handler*>const_iterator It =
Handlers.find(&typeid(*P));
if (It != Handlers.end()) (*(It->second))(P);

Is it safe?
 
M

marcwentink

Raider schreef:
reinterpret_cast<Handler*>(&DerivedHandler); ....
Is it safe?

May-be if you really know all your code, but you might use dynamic_cast
and if it would convert to null as indication you're doing something
wrong, then handle that error somehow. I have never seen this
reinterpret_cast in a C++ myself actually, but I am not a real guru I
am afraid.


http://www.cppreference.com/keywords/dynamic_cast.html

http://www.cppreference.com/keywords/reinterpret_cast.html

Marcus Wentink
 
M

Michiel.Salters

Raider said:
I have simple class hierarchy (without multiple inheritance):
class Base {};
class Derived : public Base {};
class DeepDerived : public Derived {};
// ... a lot of types

Is it ok to cast void(Base*) to void(Derived*) if I know exactly what I
will pass Derived* as a parameter?

No, definitely not. If it were, it would have been allowed.
I want to register different handlers for different types using
std::map:
typedef void Handler(Base*);
std::map<const std::type_info*, Handler*> Handlers;

Imagine code like this:
void DerivedHandler(Derived*);
Handlers[&typeid(Derived)] =
reinterpret_cast<Handler*>(&DerivedHandler);

Well, the reinterpret_cast already tells you it's unsafe. It means as
much as
"compiler, I know this is safe". Since you have to ask, you obviously
don't know.

Now, it's rather trivial to write a wrapper functor that holds a
void(Base*) and
has an operator()(Derived*), so I suggest you use that.

HTH,
Michiel Salters
 
F

Fraser Ross

Raider schreef:
May-be if you really know all your code, but you might use dynamic_cast
and if it would convert to null as indication you're doing something
wrong, then handle that error somehow. I have never seen this
reinterpret_cast in a C++ myself actually, but I am not a real guru I
am afraid.

dynamic_cast is unnecessary because he is certain of the class type
somehow. static_cast will return a pointer for an object with the
correct alignment for its type which reinterpret_cast won't necessarily
do.

Fraser.
 
A

Andrey Tarasevich

Raider said:
I have simple class hierarchy (without multiple inheritance):
class Base {};
class Derived : public Base {};
class DeepDerived : public Derived {};
// ... a lot of types

Is it ok to cast void(Base*) to void(Derived*) if I know exactly what I
will pass Derived* as a parameter?

What you actually cast in your code below is 'void (*)(Derived*)' to 'void
(*)(Base*)', not the other way around. This is not a standard conversion (in
either direction, BTW), which means that in can't be done implicitly. This cast
can be explicitly forced with 'reinterpret_cast'. However, you can't use the
resultant pointer value in order to call the function. The only thing you can do
with the resultant value is to cast it back to 'void (*)(Derived*)' at a later
time, i.e perform a "round trip" conversion 'void (*)(Derived*)' -> 'void
(*)(Base*)' -> 'void (*)(Derived*)'. The final value can be used in a call, but
the intermediate 'void (*)(Base*)' value cannot be.
I want to register different handlers for different types using
std::map:
typedef void Handler(Base*);
std::map<const std::type_info*, Handler*> Handlers;

Imagine code like this:
void DerivedHandler(Derived*);
Handlers[&typeid(Derived)] =
reinterpret_cast<Handler*>(&DerivedHandler);
Base* P = ...;
std::map<const std::type_info*, Handler*>const_iterator It =
Handlers.find(&typeid(*P));
if (It != Handlers.end()) (*(It->second))(P);

Is it safe?

No. In order to "fix" the code you'd have to complete the "round trip"
conversion by adding an extra cast:

std::map<const std::type_info*, Handler*>const_iterator It =
Handlers.find(&typeid(*P));
if (It != Handlers.end())
reinterpret_cast<void (*)(Derived*)>(t->second)(P);

But the need for a hardcoded cast essentially defeats the purpose of the code,
as I understand it. What you are trying to use is not a viable approach to
run-time type-based dispatch, as long as you care about the safety of the code.

Without knowing more details about what you are trying to implement it is hard
to understand why you even need such a dispatcher and, therefore, hard to
suggest an alternative technique. Can you provide more details?
 
M

marcwentink

Fraser Ross schreef:
dynamic_cast is unnecessary because he is certain of the class type
somehow.

Yes, you are right, but code can be changed, modified by people not so
certain what they are doing, and it could be an extra check? You need
some extra check here somewhere, for the fact when another coder
changes your code to something where things can go wrong.

I have never seen reinterpret_cast used actually. Why and where would
you use reinterpert_cast? I've been programming C++ for some years now,
and the casts frequently used are the static and dynamic.
static_cast will return a pointer for an object with the
correct alignment for its type which reinterpret_cast won't necessarily
do.

Correct alignment?
 
A

Andrey Tarasevich

Fraser Ross schreef:


Yes, you are right, but code can be changed, modified by people not so
certain what they are doing, and it could be an extra check? You need
some extra check here somewhere, for the fact when another coder
changes your code to something where things can go wrong.

I have never seen reinterpret_cast used actually. Why and where would
you use reinterpert_cast? I've been programming C++ for some years now,
and the casts frequently used are the static and dynamic.


Correct alignment?

If you read the OP's message carefully, you'll see that the OP is not talking
about conversions between 'Base*' and 'Derived*' types, but rather about
conversions between 'void (*)(Base*)' and 'void (*)(Derived*)' types. Neither
'static_cast' nor 'dynamic_cast' is applicable here. Only 'reinterpret_cast' can
be used, but its safe usage is so limited as to make it completely useless in
this case.
 
M

marcwentink

Andrey Tarasevich schreef:

conversions between 'void (*)(Base*)' and 'void (*)(Derived*)' types. Neither
'static_cast' nor 'dynamic_cast' is applicable here. Only 'reinterpret_cast' can
be used

Ah, yes, I understand, thanks!
 
R

Raider

Andrey said:
Imagine code like this:
void DerivedHandler(Derived*);
Handlers[&typeid(Derived)] =
reinterpret_cast<Handler*>(&DerivedHandler);
Base* P = ...;
std::map<const std::type_info*, Handler*>const_iterator It =
Handlers.find(&typeid(*P));
if (It != Handlers.end()) (*(It->second))(P);

Is it safe?

No. In order to "fix" the code you'd have to complete the "round trip"
conversion by adding an extra cast:

std::map<const std::type_info*, Handler*>const_iterator It =
Handlers.find(&typeid(*P));
if (It != Handlers.end())
reinterpret_cast<void (*)(Derived*)>(t->second)(P);

But the need for a hardcoded cast essentially defeats the purpose of the code,
as I understand it. What you are trying to use is not a viable approach to
run-time type-based dispatch, as long as you care about the safety of the code.

Without knowing more details about what you are trying to implement it is hard
to understand why you even need such a dispatcher and, therefore, hard to
suggest an alternative technique. Can you provide more details?

I have a layered application archirecture. Some layer is generating
event and pass it to the next and so on. I want to separate layers form
each other giving simply one door between them:

void HandleEvent(Event&);

Stright way is to create personal door for each event
class IEventHandler
{
void HandleEvent(Event1&);
void HandleEvent(Event2&);
void HandleEvent(Event3&);
....
}

But:
1. such interface will grow when adding new event types
2. each HandleEvent() will contain the same code to dispatch events by
another (not event type) characteristics - in real code I have std::map
not with typeid(Event) key, but with a tuple of event characterictics
(with typeid(Event) as not even first member).

Currently I have simple handlers registration like this:
void SomeHandler(SomeEvent&)
{
// handle event of type SomeEvent
// form MODULE_A initiated by SUBSYSTEM_X
}

int main()
{
Handlers.Register<SomeEvent>(MODULE_A, SUBSYSTEM_X, SomeHandler);
...
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top