Using raw pointers, this can be achieved like so:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class base {
public:
virtual ~base(){}
};
class derived1 : public base {
public:
virtual ~derived1(){}
derived1(const int& other) : val(other) {}
int val;
};
class derived2 : public base {
public:
virtual ~derived2(){}
derived2(const float& other) : val(other) {}
float val;
};
int main()
{
derived1 dataA = 4;
derived2 dataB = 3.0f;
std::map<std::string, base*> mapOfPointersToData; //Needs to be a pointer because it can be of type deribed1 or derived2. Cant be smart as pointing to stack memory
mapOfPointersToData["dataA"] = &dataA;
mapOfPointersToData["dataB"] = &dataB;
base* result = mapOfPointersToData["dataA"];
std::cout << dynamic_cast<derived1*>(result)->val << std::endl;
return 0;
}
This works, but I have been told that we should avoid the use of raw pointers in favour of smart pointers or references.
The objects can never be null, so it makes sense to use a reference. We can get around the problem that the map can only store one data type by using a variant:
int main()
{
derived1 dataA = 4;
derived2 dataB = 3.0f;
std::map<std::string, std::variant<derived1, derived2>&> mapOfPointersToData; //Cant be constructed
mapOfPointersToData["dataA"] = dataA;
mapOfPointersToData["dataB"] = dataB;
auto result = mapOfPointersToData["dataA"];
std::cout << std::get<derived1>(result).val << std::endl;
return 0;
}
but this gives the error
error: value-initialization of reference type ‘std::variant<derived1, derived2>&
So what is the best way to store references to stack data that can be of different types?