Reputation: 23
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
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
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