Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Determine the type of a polymorphic object at runtime

I am trying to work on a project that will require me to determine a polymorphic object's type at runtime, so that I can cast it. An example of what I mean:

class A{
};
class B: public A{
    public:
        void foo(){
            printf("B::foo()\n");
        }
};

Later, I will have a bunch of B objects that are essentially stored as such:

std::vector<A*> v;
v.push_back(new B());

And I will need to call certain overloaded methods defined as:

void bar(B* b){
    b->foo();
}

After passing in objects that are stored in v. The problem that I am having is that in my actual use-case, I don't know the type of B at compile-time, so I can't just call bar by saying bar((B*)v.get(0));

The solution I have been thinking I might need is to somehow determine the type that each object is at runtime, so that I can cast it before passing it to bar.

The solution I have tried so far was to use decltype, but it didn't work for me because it just returns the static type of the value passed in, not the type at runtime.

Also, I do not want to use third party libraries for this project, since I would like to make it as small as possible.

Thank you for your help.

Edit:

I don't think I was clear enough in what I meant when I was describing my problem. In my actual use case (which is a bit long to try posting here, though I can post parts of it if necessary), I am trying to write a library in which there is a base class (represented here as A) which can be extended by the user into their own custom classes (represented here as B). In my example, B::foo() is simply supposed to represent how each subclass of A can have its own data members that are handled later by some method (represented in my example as bar). This is also the reason why A cannot simply have some virtual foo method.

The main issue I'm having is, since B is supposed to be user-defined, I don't know what it is at compile-time, but I do at link-time (since linking comes later). That is why the use of dynamic_cast (as suggested by Sam and Remy) won't work, because from what I understand of it, it requires that I know every possibility of what B could be, which I don't. Although it did look very close to what could work for me. If there was some way to get all possible subclasses (say, with preprocessor macros or templates), then I think this might be able to work.

I hope I've explained it better this time. Thank you again for your help.

Edit 2: Another clarifying point: In the actual project I am working on, I only want the user to be required to write their own B classes and overload bar to work with their custom classes. However, I don't want the user to be required to call bar. Rather, I would like to have bar be called from a base class (that I define). That is the main reason for even attempting to do this the way I am. That, and to see if I can.

Hope that clears everything up. Thank you again.

like image 455
AFlyingCar Avatar asked May 26 '16 00:05

AFlyingCar


2 Answers

This is what virtual methods are for.

Declare the foo() virtual method in A, and you don't have to worry about doing ugly casts.

Alternatively, if A has at least one virtual function -- and a virtual destructor will do -- you can try your luck with a dynamic_cast<>.

like image 181
Sam Varshavchik Avatar answered Sep 28 '22 08:09

Sam Varshavchik


In C++, (dynamic) polymorphism is the tool for this type of thing.

struct A {
  virtual void foo() = 0;
  virtual~A() {}
};

struct B : A {
  void foo() override;
};

std::vector<std::unique_ptr<A>> vA;
vA.emplace_back(new B);
vA[0]->foo();

There is no need to find the actual type of the object pointed to by vA[0], the virtual function call mechanism will find the correct function (in this case B::foo()). Note the virtual destructor of class A. It guarantees that derived objects (of class B) are correctly deleted from a pointer to A (as kept by unique_ptr<A>).

Of course, there is also the dynamic_cast<>, which allows you to test whether the object is actually of a certain type:

auto ptr = dynamic_cast<B*>(vA[0].get());
if(ptr)   // object is a B
  std::cout<<" have B";
like image 37
Walter Avatar answered Sep 28 '22 08:09

Walter