4

Sorry for the title's wording; I don't know how to make it better. But the gist of my question is this:

#include <iostream>
using namespace std;

class Base {};
class Base2 {};
class C : public Base, public Base2 {};
class D : public Base {};

void isDerivedFromBase2(Base *p) {
    if (...) { /* test whether the "real object" pointed by p is derived from Base2? */
        cout << "true" << endl;
    }
    cout << "false" << endl;
}
int main() {
    Base *pc = new C;
    Base *pd = new D; 
    isDerivedFromBase2(pc); // prints "true"
    isDerivedFromBase2(pd); // prints "false"

    // ... other stuff
}

How do I test if an object, represented by its base class pointer Base *, is derived from another base class Base2?

Leedehai
  • 3,660
  • 3
  • 21
  • 44
  • 2
    Use `std::is_base_of` https://en.cppreference.com/w/cpp/types/is_base_of – The Unknown Jul 20 '18 at 06:55
  • 1
    @TheUnknown is_base_of doesn't work, because the second template parameter is required to be a derived class type, but now my objects are represented by `Base *`, so `decltype(*p)` is just `Base`. – Leedehai Jul 20 '18 at 06:56
  • 1
    either use `dynamic_cast` or your own `dynamic_cast` implementation but you have to create some reflection system http://preshing.com/20180116/a-primitive-reflection-system-in-cpp-part-1/ – Konrad Jul 20 '18 at 07:19
  • https://www.gamasutra.com/view/news/128978/Reflection_in_C_The_simple_implementation_of_Splinter_Cell.php – Konrad Jul 20 '18 at 07:20
  • http://www.randygaul.net/category/reflection/ – Konrad Jul 20 '18 at 07:20
  • https://stackoverflow.com/questions/579887/how-expensive-is-rtti – Konrad Jul 20 '18 at 07:21

2 Answers2

8

You can perform dynamic_cast like this:

 if (dynamic_cast<Base2 *>(p)) {

online_compiler

Unlike approach with typeid this one does not require an extra header to be included, however it relies on RTTI as well (this implies that these classes need to be polymorphic).

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • @AlanBirtles You can as long as RTTI is available. – user7860670 Jul 20 '18 at 06:50
  • @DanielLangr I've mentioned this. – user7860670 Jul 20 '18 at 06:51
  • OK.. it seems there no way around without RTTI? – Leedehai Jul 20 '18 at 07:01
  • 2
    @Leedehai: You're requesting for type information at runtime, I believe these words in a different order form RTTI ;). – rubenvb Jul 20 '18 at 07:02
  • 1
    @Leedehai Well, to figure out the type of the object pointer points to you will need to have this information available somewhere at runtime. Normal RTTI makes this information available through pointer to vtable stored in each class instance. You can make your own RTTI-like mechanism for example by storing class type enumerator value in each `Base` class instance. Another form of RTTI is to allocate objects of different types from different pools. This way you can figure out type of the object pointer points to by querying those pools. – user7860670 Jul 20 '18 at 07:16
  • Well there is a way around RTTI - LLVM uses `dyn_cast<>`, a hand-rolled `dynamic_cast<>` without many drawbacks of ordinary RTTI: [LLVM doc](http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates), but its code is far more convoluted - [github](https://github.com/llvm-mirror/llvm/blob/master/include/llvm/Support/Casting.h) – Leedehai Jul 20 '18 at 08:15
  • 1
    @Leedehai Well, it actually has exactly the same drawbacks as regular RTTI, instead of adding vtable pointer it adds a class id value of some sort. Basically it is the "make your own RTTI-like mechanism" kind of thing. – user7860670 Jul 20 '18 at 08:21
  • @Leedehai Yes, it uses templates and SFINAE, but they can provide information only about types at compile-time so the actual runtime check relies on extra field added into target class. – user7860670 Jul 20 '18 at 09:24
0

This sounds like an X-Y problem.

The need for RTTI (or the need to test an object for which class it is derived from) is typically a sign for a bad design - you simply should not ever need such a test/information.
If the hierarchy is well designed, virtual functions take on the role of these tests.

To find out what is not well-designed, ask yourself 'what I am going to do with the information once I have it?' The answer is always something of the kind 'I'll make an if/switch/... to treat them differently'; and the correct solution is to treat them the same way - call a virtual method, and each object carries the knowledge of the right virtual method which knows what it needs to get done.

Aganju
  • 6,295
  • 1
  • 12
  • 23