182

I have a class A and another class that inherits from it, B. I am overriding a function that accepts an object of type A as a parameter, so I have to accept an A. However, I later call functions that only B has, so I want to return false and not proceed if the object passed is not of type B.

What is the best way to find out which type the object passed to my function is?

lemnisca
  • 10,133
  • 3
  • 19
  • 11
  • 1
    NONE of these seem to address the root issue... `code void *p1 = new int(); void *p2 = new double(); void f(void *p) {....code goes here } f(p1) should print int... f(p2) should print double... ` – David V. Corbin Oct 26 '20 at 14:58

11 Answers11

188

dynamic_cast should do the trick

TYPE& dynamic_cast<TYPE&> (object);
TYPE* dynamic_cast<TYPE*> (object);

The dynamic_cast keyword casts a datum from one pointer or reference type to another, performing a runtime check to ensure the validity of the cast.

If you attempt to cast to pointer to a type that is not a type of actual object, the result of the cast will be NULL. If you attempt to cast to reference to a type that is not a type of actual object, the cast will throw a bad_cast exception.

Make sure there is at least one virtual function in Base class to make dynamic_cast work.

Wikipedia topic Run-time type information

RTTI is available only for classes that are polymorphic, which means they have at least one virtual method. In practice, this is not a limitation because base classes must have a virtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
yesraaj
  • 46,370
  • 69
  • 194
  • 251
  • 1
    What do you mean with there must be a virtual function in the Base class to make dynamic_cast work. That seems to me to important, that I will just guess. – GiCo Aug 19 '15 at 08:20
  • 3
    OK found it: Run-Time Type Information (RTTI) is available only for classes which are polymorphic, which means they have at least one virtual method. dynamic_cast and typeid need RTTI. – GiCo Aug 19 '15 at 08:54
  • Doesn't `dynamic_cast` throw if its not convertible? Is there a way to do it without generating a throw? – jww Aug 31 '16 at 11:38
  • Does this work for PODs that have been cast to a `uint8_t*`? That is, can I check that `uint32_t* x = dynamic_cast(p)`, where `p` is `uint8_t*`? (I'm trying to find a test for punning violations). – jww May 25 '19 at 08:46
184

Dynamic cast is the best for your description of problem, but I just want to add that you can find the class type with:

#include <typeinfo>

...
string s = typeid(YourClass).name()
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
Robocide
  • 6,353
  • 4
  • 37
  • 41
  • 8
    Good if you really don't know what your object is. The accepted answer assumes you do. – unludo Feb 28 '12 at 16:01
  • 4
    @xus Yes. it is part of std headers – Amey Jah Apr 16 '13 at 07:54
  • 9
    I [don't see](http://coliru.stacked-crooked.com/a/389a90a2e3e0713e) how. Type id names are not required to be useful and are implementation defined. – Shoe Jan 29 '14 at 16:13
  • 3
    Most interesting here: The names of instances of the same class don't have to be equal. However the typeid itself has to compare equal for instances of the same class, see https://stackoverflow.com/questions/1986418/typeid-versus-typeof-in-c – FourtyTwo Apr 13 '16 at 10:42
  • 1
    Note gcc returns the magled name e.g. `11MyClass`. To unmangle you can use the ABI extension library in `cxxabi.h`. This gives you `abi::__cxa_demangle` which will give you the real name – David G Nov 28 '16 at 18:28
  • Also check this question about the names returned by `typeid(...).name()`: https://stackoverflow.com/questions/4465872/why-does-typeid-name-return-weird-characters-using-gcc-and-how-to-make-it-prin – zardosht Jun 13 '20 at 14:43
30

This is called RTTI, but you almost surely want to reconsider your design here, because finding the type and doing special things based on it makes your code more brittle.

Luis Sandoval
  • 75
  • 2
  • 9
Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • 8
    True. Unfortunately I'm working on an existing project so I can't really go changing the design, or anything in class A. – lemnisca Dec 09 '08 at 05:23
19

Just to be complete, I'll build off of Robocide and point out that typeid can be used alone without using name():

#include <typeinfo>
#include <iostream>

using namespace std;

class A {
public:
    virtual ~A() = default; // We're not polymorphic unless we
                            // have a virtual function.
};
class B : public A { } ;
class C : public A { } ;

int
main(int argc, char* argv[])
{
    B b;
    A& a = b;

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl;
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl;
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl;
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl;
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl;
}

Output:

a is B: true
a is C: false
b is B: true
b is A: false
b is C: false
firebush
  • 5,180
  • 4
  • 34
  • 45
9

You are looking for dynamic_cast<B*>(pointer)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Joshua
  • 40,822
  • 8
  • 72
  • 132
9

Probably embed into your objects an ID "tag" and use it to distinguish between objects of class A and objects of class B.

This however shows a flaw in the design. Ideally those methods in B which A doesn't have, should be part of A but left empty, and B overwrites them. This does away with the class-specific code and is more in the spirit of OOP.

freespace
  • 16,529
  • 4
  • 36
  • 58
4

Because your class is not polymorphic. Try:

struct BaseClas { int base; virtual ~BaseClas(){} };
class Derived1 : public BaseClas { int derived1; };

Now BaseClas is polymorphic. I changed class to struct because the members of a struct are public by default.

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
c64zottel
  • 41
  • 1
3

Your description is a little confusing.

Generally speaking, though some C++ implementations have mechanisms for it, you're not supposed to ask about the type. Instead, you are supposed to do a dynamic_cast on the pointer to A. What this will do is that at runtime, the actual contents of the pointer to A will be checked. If you have a B, you'll get your pointer to B. Otherwise, you'll get an exception or null.

Uri
  • 88,451
  • 51
  • 221
  • 321
  • 1
    It should be noted you'll get an exception *only* if you perform a reference cast which fails. i.e. dynamic_cast(t). Failed pointer casts return NULL. i.e. dynamic_cast(t) – AlfaZulu Dec 09 '08 at 05:14
  • Yea, I should have clarified that better. Thanks. I wish there was a word the describe in C types that are by-reference rather than by-value. – Uri Dec 09 '08 at 05:21
3

As others indicated you can use dynamic_cast. But generally using dynamic_cast for finding out the type of the derived class you are working upon indicates the bad design. If you are overriding a function that takes pointer of A as the parameter then it should be able to work with the methods/data of class A itself and should not depend on the the data of class B. In your case instead of overriding if you are sure that the method you are writing will work with only class B, then you should write a new method in class B.

Naveen
  • 74,600
  • 47
  • 176
  • 233
3

If you can access boost library, maybe type_id_with_cvr() function is what you need, which can provide data type without removing const, volatile, & and && modifiers. Here is an simple example in C++11:

#include <iostream>
#include <boost/type_index.hpp>

int a;
int& ff() 
{
    return a;
}

int main() {
    ff() = 10;
    using boost::typeindex::type_id_with_cvr;
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl;
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl;
    std::cout << typeid(ff()).name() << std::endl;
}

Hope this is useful.

Kehe CAI
  • 1,161
  • 12
  • 18
2

Use overloaded functions. Does not require dynamic_cast or even RTTI support:

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

class Foo {
public:
    void Bar(A& a) {
        // do something
    }
    void Bar(B& b) {
        Bar(static_cast<A&>(b));
        // do B specific stuff
    }
};
jmucchiello
  • 18,754
  • 7
  • 41
  • 61
  • Right from original question: "I later call functions that only B has" - how overloading would work in such case? – Marcin Gil Dec 09 '08 at 07:11
  • When you call Bar with an A, no B stuff happens. When you call Bar with a B, methods that only exist on B can be called. Do you read the original question? Bar is his "I am overriding a function that accepts an object of type A as a parameter" – jmucchiello Dec 09 '08 at 07:20
  • 7
    This doesn't work with dynamic polymorphism, which I suspect the questioner is using. C++ can't select an overload based on the runtime class of the parameter, only based on the compile-time type. – Steve Jessop Dec 09 '08 at 12:03