Alex Shirokov
Alex Shirokov

Reputation: 23

How to deduce type of a derived class

Lets say I have a base abstract class:

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

and derived from it template class:

template<typename T>
class Derived : public Base 
{
 public:
    void function(); 
};

And another class Test, which has vector of Base class objects

 class Test
 {
 public:
 vector< Base* > base_vector;
 };

QUESTION 1: If we have a vector of pointers to objects of Base class, they can also be filled with pointers to Derived classes, right?

So, lets say now I access this vector from already existing test class, which was previously filled with pointers to objects of Derived class type

void (Test test)
{
    vector<Base*> objects = test.base_vector;
}

QUESTION 2: Is it possible to deduce the typename of the Derived objects, which pointers point to? (Derived class is a template)

OR Is it possible to call function() which was defined in Derived class, and dont care about type of the Derived class ?

If not, what are the minimal changes that should be made to any of these classes?

Upvotes: 1

Views: 1359

Answers (2)

Pavel Davydov
Pavel Davydov

Reputation: 3569

I'm not sure that I understood what you want, but will this modification of your code work for you? This way you either do not need to deduce type at all, or you can get a virtual type() method, that will return you an enum with some unique value for every type.

#include <memory>
#include <string>
#include <vector>
#include <iostream>

class Base {
public:
  virtual void function() = 0;
  virtual ~Base() = default;
};

template <class T> class Derived : public Base {
public:
  void function() override {
      // to produce some output
      std::cout << typeid(T).name() << std::endl; 
  }
};

class Test {
public:
  std::vector<std::unique_ptr<Base>> objects;
};

int main() {
  Test test;
  test.objects.push_back(std::make_unique<Derived<int>>());
  test.objects.push_back(std::make_unique<Derived<std::string>>());
  for (auto &ptr : test.objects) {
      ptr->function();
  }
}

Alternative solution to this problem is to use a variant class, for example boost::variant, or std::experimental::variant (if you standard library already has one). This way you don't need to have virtual function() in Base class. boost::variant has which() method that returns you and integer number of type in a type list. An example:

#include <boost/variant.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

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

template <class T> class Derived : public Base {
public:
  void function() {
    std::cout << typeid(T).name() << std::endl;
  }
};

class Test {
public:
  std::vector<boost::variant<Derived<int>, Derived<std::string>>> objects;
};

int main() {
  Test test;
  test.objects.push_back(Derived<int>());
  test.objects.push_back(Derived<std::string>());
  for (auto& obj : test.objects) {
    switch (obj.which()) {
      case 0:
        boost::get<Derived<int>>(obj).function();
        break;
      case 1:
        boost::get<Derived<std::string>>(obj).function();
        break;
    }
  }
  return 0;
}

Upvotes: 1

grigor
grigor

Reputation: 1624

If I understand your problem correctly then you need to use virtual functions. If you want to call a function on the objects and make sure that the function of the correct type is called then make your function virtual. So you need to declare it in your Base class. Also, you need to make your vector be a vector of pointers to Base. Then when you call your function on the objects of the vector it will call the function from the derived class if the objects are indeed of the derived type.

This way you don't need to find out the type of the objects, you'll just call the virtual function and it will find out what type of object it is and call the correct function.

Upvotes: 1

Related Questions