0

Suppose I have a base class that is an abstract interface, and two derived classes, which inherit a certain state from the base class. I want to change which derived class I'm using at run-time, but I want to preserve the shared state.

class Base{
public:
virtual void abstract() = 0;
SharedState ss;
};

class Der1 : public Base{
Der1() = default;
virtual void abstract() {//bla bla};
Der1(SharedState &s){
ss = s;};
};

class Der2 : public Base{
Der2() = default;
virtual void abstract(){//bla bla 2};
Der2(SharedState &s){
ss = s;};
};

struct SharedState{
int x,y,z;
float x1,y1,z1; 
//etc...
}

I my handler code, I have a smart pointer that changes behaviour based on class type at run-time, hence the shared state constructor.

 //driver code
std::unique_ptr<Base> ptr = std::make_unique<Der1>();

I'm planning to change the type, but with such a constructor I can preserve the state. However it is highly annoying to preface every member of the shared state with ss., is there a way to avoid this, perhaps with a using declaration of some sort?

Edit: I know I can move the shared state in the base and make it static, but that leads to performance drops when I'm not using this interface.

  • 3
    Is your question how to avoid having to type `ss.` every time you want to access the shared state? – JohnFilleau May 06 '21 at 13:19
  • @JohnFilleau yes –  May 06 '21 at 13:26
  • 1
    Don't use a struct, just put the shared state directly in `Base` as `x`, `y`, `z`, etc. – JohnFilleau May 06 '21 at 13:30
  • 1
    @JohnFilleau and when the shared state grows, how do I move it when I change the derived class in the drivers code? I would prefer to avoid a constructor with 20 parameters. –  May 06 '21 at 13:33
  • 2
    It's not nice but you could have `SharedState` be a base class of `Base` – al3c May 06 '21 at 13:57
  • @al3c didnt even think of that, thanks. it is pretty ugly, it just feels wrong somehow –  May 06 '21 at 14:07
  • Another not-so-fancy (ugly) solution is to overload the operator `->` or `[]` and do a map and get your memebr by `ptr["x"]` ... making sure you return a reference and not a copy so that you can change the values of these members – Ivan May 06 '21 at 16:09

1 Answers1

0

This is an ugly answer, but is an answer, solves the "ss" problem and can be usefull.

I overloaded the operator [] to directly return the values of your struct

struct SharedState{
int x,y,z;
float x1,y1,z1; 
//etc...
};


class Base{
public:
virtual void abstract() = 0;
SharedState ss;
public:
  int& operator[](const std::string rhs) 
  {                          
    if(rhs == "x") //Here you will manage all the struct members, probably a map
    return this->ss.x; // return the result by reference
  }
};

class Der1 : public Base{
void abstract() override { };
public:
Der1(SharedState &s){
ss = s;};
};

class Der2 : public Base{
void abstract() override { };
public:
Der2(SharedState &s){
ss = s;};
};



int main()
{
  SharedState ss;
  ss.x = 100;
  std::unique_ptr<Base> ptr = std::make_unique<Der1>(ss);
  
  std::cout << (*ptr)["x"] << std::endl;
  (*ptr)["x"] = 5; // You can change it too 
  std::cout << (*ptr)["x"] << std::endl;
  
  std::unique_ptr<Base> ptr2 = std::make_unique<Der2>(ptr->ss);
  std::cout << (*ptr2)["x"] << std::endl;
}
Ivan
  • 1,352
  • 2
  • 13
  • 31
  • you could even [do this kind of magic](https://stackoverflow.com/a/39775770/11261546) – Ivan May 06 '21 at 16:43