Casting from Base Class to Instantiated Class Template

102 Views Asked by At

I have several objects being instances of a Class Template. I need those objects to be stored in a std::vector. So I made the Class Template inherits from a Base Class:

class BaseValue
{
public:
  virtual void Test()
  {
    std::cout << "BaseValue::Test()" << std::endl;
  }
};

template<class T>
class TemplateValue : public BaseValue
{
public:
  TemplateValue(const T &value) : m_value(value)
  {
  }

  virtual void Test()
  {
    std::cout << "TemplateValue::Test() => " << m_value << std::endl;
  }

  T GetValue() const
  {
    return m_value;
  }

  void SetValue(const T &value)
  {
    m_value = value;
  }

private:
  T m_value;
};

Based on this, I would like to do something similar to this:

  TemplateValue<double> *VDouble1 = new TemplateValue<double>(42.42);
  TemplateValue<std::string> *VString2 = new TemplateValue<std::string>("Hi!");
  TemplateValue<double> *VDouble3 = new TemplateValue<double>(0);
  TemplateValue<std::string> *VString4 = new TemplateValue<std::string>("");

  std::vector<BaseValue *> values{VDouble1, VString2, VDouble3, VString4};

  // Error: class BaseValue has no member "SetValue"
  // Error: class BaseValue has no member "GetValue"
  values[2]->SetValue(values[0]->GetValue());
  values[3]->SetValue(values[1]->GetValue());

How could I do that? I was thinking about storing a typeId in the base class and use this to cast the BaseValue into their respective TemplateValue<T> and then calling SetValue(const T &value) but not sure this is a clean solution.

NOTES

  • I have no idea what are the T's actually. Some may be added in the future and it should still work.
2

There are 2 best solutions below

0
Korchkidu On BEST ANSWER

Building on @joseph-mansfield who suggested:

"Why not make SetValue and GetValue also virtual members of BaseValue?"

What I did:

In BaseValue:

  virtual void SetValue(const BaseValue *bv) = 0;

In TemplateValue

  void SetValue(const BaseValue *bv)
  {
    auto tv = static_cast<const TemplateValue<T>*>(bv);
    m_value = tv->m_value;
  }

In Main

  values[2]->SetValue(values[0]);
  values[3]->SetValue(values[1]);

The only problem is that it relies on static_cast so if the given type is not correct, I am in trouble.

2
user1810087 On

Mixing compile time polymorphism with runtime polymorphism is most impossible. I would say you can't do that like you try it now.

But you can use a specific type insteed of the template type. For example boost::variant if you have a known amount of types you want to provide.

#include <boost/variant.hpp>

using my_variants = boost::variant<int, std::string>;

class value {
public:

    value(const my_variants &value) : m_value(value) {}


    my_variants set() const {
        return m_value;
    }

    void get(const my_variants &value) {
        m_value = value;
    }

private:
    my_variants m_value;
};

see this running example.