How do I check if an object's type is a particular subclass in C++?
Asked Answered
D

15

114

I was thinking along the lines of using typeid() but I don't know how to ask if that type is a subclass of another class (which, by the way, is abstract)

Debonair answered 21/11, 2008 at 3:41 Comment(2)
I just wonder if there is a way to check if an object's type is a particular subclass at compile-time in C++, because std::is_base_of won't work as desired. :3Instruct
Can you please elaborate on "std::is_base_of won't work as desired"? I tried it out using both gcc C++20 and VS C++17; it gave me a compiler error when the class was not derived from the base. For example, for the two structures struct A {}; and struct B {};, the line static_assert (std::is_base_of_v <A, B>); fails at compile time, but for struct DerivedFromA : public A {}; , the line static_assert (std::is_base_of_v<A, DerivedFromA>); compiles fine.Puga
H
53

You really shouldn't. If your program needs to know what class an object is, that usually indicates a design flaw. See if you can get the behavior you want using virtual functions. Also, more information about what you are trying to do would help.

I am assuming you have a situation like this:

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

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

If this is what you have, then try to do something like this:

class Base
{
  virtual void bar() = 0;
};

class A : public Base
{
  void bar() {/* do X */}
};

class B : public Base
{
  void bar() {/* do Y */}
};

void foo(Base *p)
{
  p->bar();
}

Edit: Since the debate about this answer still goes on after so many years, I thought I should throw in some references. If you have a pointer or reference to a base class, and your code needs to know the derived class of the object, then it violates Liskov substitution principle. Uncle Bob calls this an "anathema to Object Oriented Design".

Hungary answered 21/11, 2008 at 3:57 Comment(29)
+1. I think the correct name for this is "Tell, don't ask". Basically, always favour polymorphism (TELLing an object what to do, letting the implementation take care of it) over a case/if statement where you ASK to find out what type of object you are dealing with.Darlleen
yep - this is all good - but the guy wanted to know about how to resolve typeFlorida
JohnIdol, I get it. And it is still a bad idea.Hungary
@Dima, and what if someone wants to know the syntax just for learning purposes (let's say they are going through a book written in Java, about design flaws, and they need to translate that to C++)?Kerseymere
I need to find out the type of an object for debugging purposes, because I need to know what strange objects are getting inserted into my dictionary and making it crash. Is there no hope? dynamic_cast seems infeasible, because the object's type could be almost anything.Secede
A common usecase for doing this (at least in Java) is when comparing two objects for equality. Usually you want to check if they are of the same subclass before checking the required properties for equality.Awoke
@Hungary Ever worked with external library that defines superclasses? Try applying your answer there please.Sheldonshelduck
@TomášZato, you can certainly find cases where you may want to know the actual type of the object. However, that still means that you are fighting the language, and that there is an underlying design flaw. The flaw may well be in a third party library, but it is still a flaw. If you have no control over it, then you have to live with it. If you do have control, then you should think about fixing the underlying design.Hungary
This is just your personal opinion, with no offense. I, on the contrary, do not see anything wrong with casting supertypes to their derived classes when necessary. Actually, that's huge portion of OOP use - pipelining similar data through some generic process, but treating them individually in the end.Sheldonshelduck
@TomášZato, This is more than just my personal opinion. If you need to know the derived type of the object, then your design violates Liskov substitution principle: en.wikipedia.org/wiki/Liskov_substitution_principle Here is a paper by Robert C. Martin, where he specifically talks about why asking for the type of object is violation of LSP, and why it is an "anathema to Object Oriented Design": objectmentor.com/resources/articles/lsp.pdfHungary
This answer makes the rather huge assumption that you have control over the types you need to cast to and can rewrite them... For example I'm adding a feature to a GUI library based on another GUI library, and I need to know if the parent of a widget is scrollable. The original library offers no way to test this so I have to try and cast my widgets parent to the base-class of scrollable widgets, which really sucks. Anyway the point is that you left out the actual answer to the question at hand.Hovis
One valid use is when testing that a factory that returns a pointer to an interface makes an instance of a particular subclass for a given set of inputs.Lindblad
@mabraham, with all due respect, this is incorrect. If a factory returns a pointer to an interface, and you still need to know the actual subclass, then it is not a very good interface. The whole point of an interface is to abstract away the underlying subclass, i. e. to allow you to use it without knowing what the underlying subclass is.Hungary
@Hungary For production code, I agree with you. But the job of a factory is to make the right subclass depending on its inputs. It is possible to test the factory and each subclass together by verifying that the properties of the subclass are consistent with the inputs. But if there's a bug, then such a test won't help anyone tell whether the issue is in the factory or the subclass it builds. Verifying the type of the subclass is one way of achieving separation in such tests.Lindblad
@Lindblad Why not have separate tests for the subclasses, where the objects are created without the factory? That would separate the bugs in the subclass from the bugs in the factory.Hungary
@Hungary That could work, but for maintainability you would want a way of keeping the coverage of combined factory+subclasses identical with subclasses on their own, so that failure of the combined test would clearly identify the factory. That could easily be more code than testing separately - particularly if the factory makes the same subclass for different input combinations but you have to assert on all the behaviours of that subclass. Thus I think it is useful to recognize that the job of a factory is to make particular subclasses, and so it is valid to verify the concrete subclass type.Lindblad
@Lindblad I am not sure I am following... The tests for subclass behavior do not need the factory, if you can create their objects directly. On the other hand, the tests for the factory should just be testing that it successfully creates the right kind of object. It should be possible to verify that with a simple test, without checking all the possible behaviors of the object, and without having to query the object's underlying type. I think it makes a lot of sense to separate the tests for the factory and for the objects that it produces.Hungary
@Hungary Yes, the subclasses should generally be testable in isolation from the factory, and the factory should be verified with a simple test. That's where verifying the type is useful. Imagine making a set of nine subclasses, each with three behaviours, each of which come in three flavours. I can't think of a simple test of the factory other than the type of the subclass. Testing all three behaviours for all nine subclasses risks re-implementing the factory logic.Lindblad
Since when coproducts became a design flaw? And no, this not necessarily break Liskov's principle. E.g. I have a class Tree, and subclasses Node and Leaf, and I wanna branch on whether I got to the Leaf. How do I violate Liskov's rule?Savonarola
@Hungary Downvoted because it doesn't answer the question. Not everyone has the liberty of working with perfectly designed code.Traceable
This is why StackOverflow is better off not being opinionated. I can actually argue against LSP itself. For example, having a priority list implement list would result in cleaner code (since it'll save me from implementing code already implemented in a list class), but many things about priority lists are obviously not true about lists. So I agree with @TomášZato, it is a matter of personal opinion. Why give higher priority to LSP over cleaner code? Why must LSP be guaranteed in the first place? Wouldn't casting be entirely unnecessary if LSP were required of OOP?Cumine
@Hungary Even better, every class in most OOP implements an Object type. However, "Object A has fur" is not always true, but Mammal, which inherits Object, will generally always uphold the statement "Mammal A has fur". So I can pretty much put LSP itself to question here. Again, stick to answering the question. That way, we leave unnecessary debates out of the way.Cumine
This is one of the reasons I tend to hesitate to come to StackOverflow for programming problems - The question doesn't ask if one should do it - It asks how to do it. I do this all the time in Java using the instanceof operator in Java. In my specific case now in C++, I'm rendering objects in a paint routine for a custom widget in QT & while sure I could add a vfunc to return the rectangle for the item I want to render, I don't b/c I already have b/w 6 & 12 vfuncs already which creates a pain when subclassing as you have to have the exact spelling right. You can do it either way.Chandelle
There should be no debate on this answer: it's simply not answering the question. If someone asks "How to shoot myself in the foot" then the answer shouldn't be "Please don't".Ewald
@WhatsUp, seriously?Hungary
This works only in books for those who never wrote any useful line of code but samples of the "ideal design" which does not exist in a real world. In some cases you might avoid checking and down casting and it will require lots of unnecessary code bloat, god objects or data copies. That's why we see lots of preprocessors and code generators and crazy build systems on top of c++ in real products which try to do what should actually be done in a language stating itself as OOP.Conant
@MrD, I have first encountered C++ in 1994, and since then I have written quite a bit of C++ code. I hope at least some of it was useful, since I was payed for it. I have indeed seen a lot of code bloat, god objects, etc., but I have found that this is usually the fault of the programmers who don't clean things up, and not the fault of the language. You can write bad code in any language, and you can also write good code in any language. This does not change the fact that asking the object about its type is bad thing. Tell, don't ask.Hungary
I am trying to understand what may be a better solution than casting to a subtype in a certain situation. I have a collection of nodes in a graph, that have shared functionality and properties. Now there are some types of nodes in the collection that have special functionality (special nodes). Using the collection, I want to find a special node and perform its special functionality, however, since the collection only knows about the base node type, I need to cast a node to a special node. Is this a bad design? Should the base type declare virtual methods for every special node type?Outdare
@JacobMellin, there are different ways to address this, depending on what you are trying to do. Maybe you can have a virtual function in the base class that does nothing for "regular" nodes, and is overridden in the special node class to perform its special thing. Then you just call this function on every node, and get the right behavior. Maybe the special nodes do not need to be of a different subclass, and the base node class can have a flag that you can check. Or maybe you can extract the special functionality in a separate class, and make it a member of Node.Hungary
Y
157

 

class Base
{
  public: virtual ~Base() {}
};

class D1: public Base {};

class D2: public Base {};

int main(int argc,char* argv[]);
{
  D1   d1;
  D2   d2;

  Base*  x = (argc > 2)?&d1:&d2;

  if (dynamic_cast<D2*>(x) == nullptr)
  {
    std::cout << "NOT A D2" << std::endl;
  }
  if (dynamic_cast<D1*>(x) == nullptr)
  {
    std::cout << "NOT A D1" << std::endl;
  }
}
Yousuf answered 21/11, 2008 at 4:1 Comment(5)
Do you really need a dynamic_cast<> here? Wouldn't a static_cast<> be enough?Astigmatism
@krlmlr. Can you tell the type of x at compile time? If so then static_cast<>() would work. If you can't tell the type of x until runtime then you need dynamic_cast<>()Yousuf
Thanks. I'm using downcasts mostly in the CRTP, I keep forgetting about other use cases ;-)Astigmatism
Good answer, but something to note here. The ternary conditional operator requires its second and third operands to have the same type. Therefore idk how this can work for anybody this way, use an if/else instead. Maybe this worked in the past? Anyhow.Dab
@Nikos, It works because: 1. C++ does not require ternary's cases be the same type, 2. They're type of derived class pointer, and derived class pointer implicity casts to base.Candida
H
53

You really shouldn't. If your program needs to know what class an object is, that usually indicates a design flaw. See if you can get the behavior you want using virtual functions. Also, more information about what you are trying to do would help.

I am assuming you have a situation like this:

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

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

If this is what you have, then try to do something like this:

class Base
{
  virtual void bar() = 0;
};

class A : public Base
{
  void bar() {/* do X */}
};

class B : public Base
{
  void bar() {/* do Y */}
};

void foo(Base *p)
{
  p->bar();
}

Edit: Since the debate about this answer still goes on after so many years, I thought I should throw in some references. If you have a pointer or reference to a base class, and your code needs to know the derived class of the object, then it violates Liskov substitution principle. Uncle Bob calls this an "anathema to Object Oriented Design".

Hungary answered 21/11, 2008 at 3:57 Comment(29)
+1. I think the correct name for this is "Tell, don't ask". Basically, always favour polymorphism (TELLing an object what to do, letting the implementation take care of it) over a case/if statement where you ASK to find out what type of object you are dealing with.Darlleen
yep - this is all good - but the guy wanted to know about how to resolve typeFlorida
JohnIdol, I get it. And it is still a bad idea.Hungary
@Dima, and what if someone wants to know the syntax just for learning purposes (let's say they are going through a book written in Java, about design flaws, and they need to translate that to C++)?Kerseymere
I need to find out the type of an object for debugging purposes, because I need to know what strange objects are getting inserted into my dictionary and making it crash. Is there no hope? dynamic_cast seems infeasible, because the object's type could be almost anything.Secede
A common usecase for doing this (at least in Java) is when comparing two objects for equality. Usually you want to check if they are of the same subclass before checking the required properties for equality.Awoke
@Hungary Ever worked with external library that defines superclasses? Try applying your answer there please.Sheldonshelduck
@TomášZato, you can certainly find cases where you may want to know the actual type of the object. However, that still means that you are fighting the language, and that there is an underlying design flaw. The flaw may well be in a third party library, but it is still a flaw. If you have no control over it, then you have to live with it. If you do have control, then you should think about fixing the underlying design.Hungary
This is just your personal opinion, with no offense. I, on the contrary, do not see anything wrong with casting supertypes to their derived classes when necessary. Actually, that's huge portion of OOP use - pipelining similar data through some generic process, but treating them individually in the end.Sheldonshelduck
@TomášZato, This is more than just my personal opinion. If you need to know the derived type of the object, then your design violates Liskov substitution principle: en.wikipedia.org/wiki/Liskov_substitution_principle Here is a paper by Robert C. Martin, where he specifically talks about why asking for the type of object is violation of LSP, and why it is an "anathema to Object Oriented Design": objectmentor.com/resources/articles/lsp.pdfHungary
This answer makes the rather huge assumption that you have control over the types you need to cast to and can rewrite them... For example I'm adding a feature to a GUI library based on another GUI library, and I need to know if the parent of a widget is scrollable. The original library offers no way to test this so I have to try and cast my widgets parent to the base-class of scrollable widgets, which really sucks. Anyway the point is that you left out the actual answer to the question at hand.Hovis
One valid use is when testing that a factory that returns a pointer to an interface makes an instance of a particular subclass for a given set of inputs.Lindblad
@mabraham, with all due respect, this is incorrect. If a factory returns a pointer to an interface, and you still need to know the actual subclass, then it is not a very good interface. The whole point of an interface is to abstract away the underlying subclass, i. e. to allow you to use it without knowing what the underlying subclass is.Hungary
@Hungary For production code, I agree with you. But the job of a factory is to make the right subclass depending on its inputs. It is possible to test the factory and each subclass together by verifying that the properties of the subclass are consistent with the inputs. But if there's a bug, then such a test won't help anyone tell whether the issue is in the factory or the subclass it builds. Verifying the type of the subclass is one way of achieving separation in such tests.Lindblad
@Lindblad Why not have separate tests for the subclasses, where the objects are created without the factory? That would separate the bugs in the subclass from the bugs in the factory.Hungary
@Hungary That could work, but for maintainability you would want a way of keeping the coverage of combined factory+subclasses identical with subclasses on their own, so that failure of the combined test would clearly identify the factory. That could easily be more code than testing separately - particularly if the factory makes the same subclass for different input combinations but you have to assert on all the behaviours of that subclass. Thus I think it is useful to recognize that the job of a factory is to make particular subclasses, and so it is valid to verify the concrete subclass type.Lindblad
@Lindblad I am not sure I am following... The tests for subclass behavior do not need the factory, if you can create their objects directly. On the other hand, the tests for the factory should just be testing that it successfully creates the right kind of object. It should be possible to verify that with a simple test, without checking all the possible behaviors of the object, and without having to query the object's underlying type. I think it makes a lot of sense to separate the tests for the factory and for the objects that it produces.Hungary
@Hungary Yes, the subclasses should generally be testable in isolation from the factory, and the factory should be verified with a simple test. That's where verifying the type is useful. Imagine making a set of nine subclasses, each with three behaviours, each of which come in three flavours. I can't think of a simple test of the factory other than the type of the subclass. Testing all three behaviours for all nine subclasses risks re-implementing the factory logic.Lindblad
Since when coproducts became a design flaw? And no, this not necessarily break Liskov's principle. E.g. I have a class Tree, and subclasses Node and Leaf, and I wanna branch on whether I got to the Leaf. How do I violate Liskov's rule?Savonarola
@Hungary Downvoted because it doesn't answer the question. Not everyone has the liberty of working with perfectly designed code.Traceable
This is why StackOverflow is better off not being opinionated. I can actually argue against LSP itself. For example, having a priority list implement list would result in cleaner code (since it'll save me from implementing code already implemented in a list class), but many things about priority lists are obviously not true about lists. So I agree with @TomášZato, it is a matter of personal opinion. Why give higher priority to LSP over cleaner code? Why must LSP be guaranteed in the first place? Wouldn't casting be entirely unnecessary if LSP were required of OOP?Cumine
@Hungary Even better, every class in most OOP implements an Object type. However, "Object A has fur" is not always true, but Mammal, which inherits Object, will generally always uphold the statement "Mammal A has fur". So I can pretty much put LSP itself to question here. Again, stick to answering the question. That way, we leave unnecessary debates out of the way.Cumine
This is one of the reasons I tend to hesitate to come to StackOverflow for programming problems - The question doesn't ask if one should do it - It asks how to do it. I do this all the time in Java using the instanceof operator in Java. In my specific case now in C++, I'm rendering objects in a paint routine for a custom widget in QT & while sure I could add a vfunc to return the rectangle for the item I want to render, I don't b/c I already have b/w 6 & 12 vfuncs already which creates a pain when subclassing as you have to have the exact spelling right. You can do it either way.Chandelle
There should be no debate on this answer: it's simply not answering the question. If someone asks "How to shoot myself in the foot" then the answer shouldn't be "Please don't".Ewald
@WhatsUp, seriously?Hungary
This works only in books for those who never wrote any useful line of code but samples of the "ideal design" which does not exist in a real world. In some cases you might avoid checking and down casting and it will require lots of unnecessary code bloat, god objects or data copies. That's why we see lots of preprocessors and code generators and crazy build systems on top of c++ in real products which try to do what should actually be done in a language stating itself as OOP.Conant
@MrD, I have first encountered C++ in 1994, and since then I have written quite a bit of C++ code. I hope at least some of it was useful, since I was payed for it. I have indeed seen a lot of code bloat, god objects, etc., but I have found that this is usually the fault of the programmers who don't clean things up, and not the fault of the language. You can write bad code in any language, and you can also write good code in any language. This does not change the fact that asking the object about its type is bad thing. Tell, don't ask.Hungary
I am trying to understand what may be a better solution than casting to a subtype in a certain situation. I have a collection of nodes in a graph, that have shared functionality and properties. Now there are some types of nodes in the collection that have special functionality (special nodes). Using the collection, I want to find a special node and perform its special functionality, however, since the collection only knows about the base node type, I need to cast a node to a special node. Is this a bad design? Should the base type declare virtual methods for every special node type?Outdare
@JacobMellin, there are different ways to address this, depending on what you are trying to do. Maybe you can have a virtual function in the base class that does nothing for "regular" nodes, and is overridden in the special node class to perform its special thing. Then you just call this function on every node, and get the right behavior. Maybe the special nodes do not need to be of a different subclass, and the base node class can have a flag that you can check. Or maybe you can extract the special functionality in a separate class, and make it a member of Node.Hungary
A
36

You can do it with dynamic_cast (at least for polymorphic types).

Actually, on second thought--you can't tell if it is SPECIFICALLY a particular type with dynamic_cast--but you can tell if it is that type or any subclass thereof.

template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
  return dynamic_cast<const DstType*>(src) != nullptr;
}
Aney answered 21/11, 2008 at 4:5 Comment(3)
When is a subclass not a polymorphic type?Sometime
@OllieFord: when there aren't any virtual functions.Aney
Said differently, when std::is_polymorphic_v<T> is false.Groggery
M
16

The code below demonstrates 3 different ways of doing it:

  • virtual function
  • typeid
  • dynamic_cast
#include <iostream>
#include <typeinfo>
#include <typeindex>

enum class Type {Base, A, B};

class Base {
public:
    virtual ~Base() = default;
    virtual Type type() const {
        return Type::Base;
    }
};

class A : public Base {
    Type type() const override {
        return Type::A;
    }
};

class B : public Base {
    Type type() const override {
        return Type::B;
    }
};

int main()
{
    const char *typemsg;
    A a;
    B b;
    Base *base = &a;             // = &b;    !!!!!!!!!!!!!!!!!
    Base &bbb = *base;

    // below you can replace    base    with  &bbb    and get the same results

    // USING virtual function
    // ======================
    // classes need to be in your control
    switch(base->type()) {
    case Type::A:
        typemsg = "type A";
        break;
    case Type::B:
        typemsg = "type B";
        break;
    default:
        typemsg = "unknown";
    }
    std::cout << typemsg << std::endl;

    // USING typeid
    // ======================
    // needs RTTI. under gcc, avoid -fno-rtti
    std::type_index ti(typeid(*base));
    if (ti == std::type_index(typeid(A))) {
        typemsg = "type A";
    } else if (ti == std::type_index(typeid(B))) {
        typemsg = "type B";
    } else {
        typemsg = "unknown";
    }
    std::cout << typemsg << std::endl;

    // USING dynamic_cast
    // ======================
    // needs RTTI. under gcc, avoid -fno-rtti
    if (dynamic_cast</*const*/ A*>(base)) {
        typemsg = "type A";
    } else if (dynamic_cast</*const*/ B*>(base)) {
        typemsg = "type B";
    } else {
        typemsg = "unknown";
    }
    std::cout << typemsg << std::endl;
}

The program above prints this:

type A
type A
type A
Mannerless answered 10/7, 2019 at 19:39 Comment(1)
This is quite a nice answer, any idea about performance? Seems like virtual would be fastest here & dynamic slowest?Phoney
T
6

dynamic_cast can determine if the type contains the target type anywhere in the inheritance hierarchy (yes, it's a little-known feature that if B inherits from A and C, it can turn an A* directly into a C*). typeid() can determine the exact type of the object. However, these should both be used extremely sparingly. As has been mentioned already, you should always be avoiding dynamic type identification, because it indicates a design flaw. (also, if you know the object is for sure of the target type, you can do a downcast with a static_cast. Boost offers a polymorphic_downcast that will do a downcast with dynamic_cast and assert in debug mode, and in release mode it will just use a static_cast).

Twelfthtide answered 21/11, 2008 at 4:49 Comment(0)
F
6

I don't know if I understand your problem correctly, so let me restate it in my own words...

Problem: Given classes B and D, determine if D is a subclass of B (or vice-versa?)

Solution: Use some template magic! Okay, seriously you need to take a look at LOKI, an excellent template meta-programming library produced by the fabled C++ author Andrei Alexandrescu.

More specifically, download LOKI and include header TypeManip.h from it in your source code then use the SuperSubclass class template as follows:

if(SuperSubClass<B,D>::value)
{
...
}

According to documentation, SuperSubClass<B,D>::value will be true if B is a public base of D, or if B and D are aliases of the same type.

i.e. either D is a subclass of B or D is the same as B.

I hope this helps.

edit:

Please note the evaluation of SuperSubClass<B,D>::value happens at compile time unlike some methods which use dynamic_cast, hence there is no penalty for using this system at runtime.

Farika answered 21/11, 2008 at 16:43 Comment(0)
S
4

I disagree that you should never want to check an object's type in C++. If you can avoid it, I agree that you should. Saying you should NEVER do this under any circumstance is going too far though. You can do this in a great many languages, and it can make your life a lot easier. Howard Pinsley, for instance, showed us how in his post on C#.

I do a lot of work with the Qt Framework. In general, I model what I do after the way they do things (at least when working in their framework). The QObject class is the base class of all Qt objects. That class has the functions isWidgetType() and isWindowType() as a quick subclass check. So why not be able to check your own derived classes, which is comparable in it's nature? Here is a QObject spin off of some of these other posts:

class MyQObject : public QObject
{
public:
    MyQObject( QObject *parent = 0 ) : QObject( parent ){}
    ~MyQObject(){}

    static bool isThisType( const QObject *qObj )
    { return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); }
};

And then when you are passing around a pointer to a QObject, you can check if it points to your derived class by calling the static member function:

if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";
Supersonics answered 19/12, 2015 at 21:31 Comment(0)
K
4
#include <stdio.h>
#include <iostream.h>

class Base
{
  public: virtual ~Base() {}

  template<typename T>
  bool isA() {
    return (dynamic_cast<T*>(this) != NULL);
  }
};

class D1: public Base {};
class D2: public Base {};
class D22: public D2 {};

int main(int argc,char* argv[]);
{
  D1*   d1  = new D1();
  D2*   d2  = new D2();
  D22*  d22 = new D22();

  Base*  x = d22;

  if( x->isA<D22>() )
  {
    std::cout << "IS A D22" << std::endl;
  }
  if( x->isA<D2>() )
  {
    std::cout << "IS A D2" << std::endl;
  }
  if( x->isA<D1>() )
  {
    std::cout << "IS A D1" << std::endl;
  }
  if(x->isA<Base>() )
  {
    std::cout << "IS A Base" << std::endl;
  }
}

Result:

IS A D22
IS A D2
IS A Base
Kauffman answered 26/5, 2017 at 17:0 Comment(0)
C
2

I was thinking along the lines of using typeid()...

Well, yes, it could be done by comparing: typeid().name(). If we take the already described situation, where:

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

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

A possible implementation of foo(Base *p) would be:

#include <typeinfo>

void foo(Base *p)
{
    if(typeid(*p) == typeid(A))
    {
        // the pointer is pointing to the derived class A
    }  
    else if (typeid(*p).name() == typeid(B).name()) 
    {
        // the pointer is pointing to the derived class B
    }
}
Colubrine answered 6/6, 2017 at 22:31 Comment(2)
Why do you mix comarison of typeid().name() and typeid()? Why not always comparing typeid()?Advocacy
I believe to show that they will both achieve the sameBlair
E
2

I see some good answers here and I see some dumb response.

"Trying to query the type of an object is a design flaw". Which means that Java instanceof and C# is keywords are design flaws. These are response of people that dont rate polymorphism. If you have an interface, that interface is derived by another interface that impelments more features. If you need these extra features you must first check that you have such an interface. Even microsoft COM API makes use of this design.

Then in terms of how to deduce if an object is a instanceof a class, many good answers have already been given

  • typeid
  • having a virtual type function
  • dynamic cast

is_base_of has nothing to do with polymorphism.

And having each virtual function define its own type method is unnecessary as it is redundant. Each virtual class already has a pointer to its virtual table.

class Base
{
 void *p_virtual_table = BASE_VIRTUAL_TABLE;
}

class Derived : Base
{
 void *p_virtual_table = DERIVED_VIRTUAL_TABLE;
}

void *BASE_VIRTUAL_TABLE[n];
void *DERIVED_VIRTUAL_TABLE[n];

The point here is that the address of the virtual tables are fixed and a simple comparrison will decide if a virtual object is an instanceof a virtual class.

Since cpp doesnt give us a standard way of accessing the virtual tables, it would be hard to do these comparrisons manually. But the cpp abstract machine has absolutely no problems deducing the exact instance of a virtual object.

Edrisedrock answered 7/6, 2021 at 6:4 Comment(1)
Another example of a modern system that uses this design pattern is LLVM. Indeed, in LLVM 11 and higher, CallBase no longer has isInvoke() to determine if the instruction is an InvokeInst, instead favoring the isa<InvokeInst> and dyn_cast<InvokeInst> calls. These use LLVM's version of RTTI, so the costs may be different than a normal dynamic_cast<>. The more important point is that this design pattern is fundamental to an extremely modern and important piece of software, and as @Edrisedrock observes, virtual type functions are not the preferred way to implement the pattern.Malcommalcontent
K
1

You can only do it at compile time using templates, unless you use RTTI.

It lets you use the typeid function which will yield a pointer to a type_info structure which contains information about the type.

Read up on it at Wikipedia

Klockau answered 21/11, 2008 at 3:55 Comment(1)
Voted up for mentioning RTTI in this context, which everybody else just ignored.Inconsonant
M
1

You can do it with templates (or SFINAE (Substitution Failure Is Not An Error)). Example:

#include <iostream>

class base
{
public:
    virtual ~base() = default;
};

template <
    class type,
    class = decltype(
        static_cast<base*>(static_cast<type*>(0))
    )
>
bool check(type)
{
    return true;
}

bool check(...)
{
    return false;
}

class child : public base
{
public:
    virtual ~child() = default;
};

class grandchild : public child {};

int main()
{
    std::cout << std::boolalpha;

    std::cout << "base:       " << check(base())       << '\n';
    std::cout << "child:      " << check(child())      << '\n';
    std::cout << "grandchild: " << check(grandchild()) << '\n';
    std::cout << "int:        " << check(int())        << '\n';

    std::cout << std::flush;
}

Output:

base:       true
child:      true
grandchild: true
int:        false
Mixtec answered 20/12, 2020 at 13:16 Comment(0)
S
1

As a spin off of multiple other answers (including one I previously posted myself!), here's a macro to help:

#define isInstance( ptr, clazz ) (dynamic_cast<const clazz*>(ptr) != NULL)
Supersonics answered 4/11, 2021 at 21:0 Comment(0)
G
0

I define 2 macros for pointer and reference params. If you're consistent with one version, you can comment out the other and re-name it as INSTANCEOF only.

#include <iostream>


#define INSTANCEOF_REF(derivedType, baseREF) (dynamic_cast<derivedType*>(&baseREF) != nullptr)
#define INSTANCEOF_PTR(derivedType, basePTR) (dynamic_cast<derivedType*>(basePTR) != nullptr)

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {
};

int main() {
    Derived derivedObj; 
    Base* baseptr = &derivedObj;

    if (INSTANCEOF_REF(Derived, derivedObj)) {
        std::cout << "derivedObj is an instance of Derived." << std::endl;
    } else {
        std::cout << "derivedObj is NOT an instance of Derived." << std::endl;
    }  
    if (INSTANCEOF_REF(Base, derivedObj)) {
        std::cout << "derivedObj is an instance of Base." << std::endl;
    } else {
        std::cout << "derivedObj is NOT an instance of Base." << std::endl;
    }  

    if (INSTANCEOF_PTR(Derived, baseptr)) {
        std::cout << "baseptr is an instance of Derived." << std::endl;
    } else {
        std::cout << "baseptr is NOT an instance of Derived." << std::endl;
    } 
    
    if (INSTANCEOF_PTR(Base, baseptr)) {
        std::cout << "baseptr is an instance of Base." << std::endl;
    } else {
        std::cout << "baseptr is NOT an instance of Base." << std::endl;
    }

    return 0;
}

======

derivedObj is an instance of Derived.
derivedObj is an instance of Base.
baseptr is an instance of Derived.
baseptr is an instance of Base.
Garnes answered 5/7, 2023 at 11:58 Comment(0)
C
-3

In c# you can simply say:

if (myObj is Car) {

}
Calefaction answered 21/11, 2008 at 3:49 Comment(3)
I answered this before the poster edit-ed his question and indicated his language choice.Calefaction
I am upvoting, it's not answer's fault that the OP specified his request.Sheldonshelduck
Sorry, have to down-vote since it does not answer the question and for some reason is shown above the answers below.Criminality

© 2022 - 2024 — McMap. All rights reserved.