rwst
rwst

Reputation: 2675

dynamic_cast type checking functionality without the cast?

There are a lot of question on the subject, but none seem to address this specifically: Given a code base that does not allow everything solved with virtual functions (as you would do normally) there is a function:

/** Check if obj is a T, including base classes. */
template <class T>
inline bool is_a(const basic &obj)
{
    return dynamic_cast<const T *>(&obj) != 0;
}

But obviously the cast is made even if unnecessary. How to write this function to check only, i.e., using the dynamic_cast functionality without doing the actual cast? Assume that it is impractical to replace calls to this function with virtual functions, or to implement a poor man's RTTI for the purpose.

EDIT: added question mark to title emphasizing the doubt about the possibility

Upvotes: 1

Views: 2293

Answers (3)

celtschk
celtschk

Reputation: 19721

Note that the actual cast is just adding an offset to the pointer. Any steps needed to determine that offset are also needed to determine whether the cast is possible at all. And a good optimizer will optimize out that final addition anyway, as adding a constant to a non-null pointer that is not used except for a null test does not have an effect.

Therefore any replacement that doesn't improve the design would have no measurable effect; the correct replacement if a better design is not possible for some reason is therefore to leave the function as it is.

Upvotes: 5

David Haim
David Haim

Reputation: 26486

dynamic_cast() will also fail if the base class is not polymorphic , meaning it doesn't have any virtual methods. meaning that B may inherit from A, but dynamic_cast() on B* to A* will fail because A doesn't have any virtual function .

luckily , we have C++11 : std::is_base_of<> : http://en.cppreference.com/w/cpp/types/is_base_of

which works even if A and B aren't polymorphic , and it also works on compile time, meaning no run-time overhead

Example :

class A {};
class B : public A{};

int main (){
B b;
if (std::is_base_of<A,decltype(b)>::value){
   std::cout<<"b can be up-cast to A*";
}
return 0;
}

(can be viewed in : http://coliru.stacked-crooked.com/a/a5612738047ff3a5)

make sure to remove any reference or pointer beforehand with std::remove_pointer and std::remove_reference if dealing with with them

Upvotes: 1

Puppy
Puppy

Reputation: 146910

There is no equivalent functionality. You've only got two alternatives.

  1. Start hand-rolling RTTI (the worst option) including visitors.
  2. Just keep using dynamic_cast.

I don't know why you even care about preventing the pointer adjustment, because it's a fairly trivial case of a couple of vtable lookups (into vtables that are already in cache) and performing a couple of subtractions. All of the actual work of dynamic_cast would be done in both cases. Furthermore, I don't see what use the result of is_a would be without casting the pointer to that type.

There is no easy way to do what you want, principally because it doesn't really make sense and therefore nobody decided to provide it.

Upvotes: 1

Related Questions