简体   繁体   中英

Changing the base class of an Object dynamically in C++

I have two classes Sensor1 & Sensor2 which inherits from class Sensor. I am creating class Camera for which the base class should be Sensor1 or Sensor2 based on some condition in the run-time. Is it possible?

One way is to create a pointer member for Sensor in Camera and then assign to Sensor1 or Sensor2 (based on condition) and in that case for all the methods of Sensor, I need to create the methods in Camera (setResolution & changeMode) and call the corresponding methods (which I want to avoid)

class Sensor {
 public:
       Sensor(){}
       ~Sensor(){}
       void setResolution(int w, int h) {};
       void changeMode(int mode) {};
}

class Sensor1: public Sensor {
  public:
       Sensor1(){}
       ~Sensor1(){}
       void setResolution(int w, int h) {\** change based on sensor **\}
       void changeMode(int mode) {\** sensor specific implementation **\}
}

class Sensor2: public Sensor {
   public:
       Sensor2(){}
       ~Sensor2(){}
       void setResolution(int w, int h) {\** change based on sensor **\}
       void changeMode(int mode) {\** sensor specific implementation **\}

class Camera: public Sensor {
   public:
       Camera (bool flag){
       //Change base class to either Sensor1 or Sensor2 which inherits from common base class Sensor
       }
       ~Camera(){}
}

This is a great place to use something like the Strategy pattern.

Instead of changing your base class for Camera , let Camera contain a pointer to either Sensor1 or Sensor2 . That's where you check your condition.

If the two classes Sensor1 and Sensor2 inherit from a common base (like Sensor ), the pattern is very simple to implement.

My C++ is a bit rusty, so see this as either code or pseudocode, depending on how valid it ends up being:

class Camera {
private:
  Sensor* obj;
public:
  Camera (bool flag){
    if (flag) {
      obj = new Sensor1();
    } else {
      obj = new Sensor2();
    }
  }
}

You could also provide functions (one for Sensor1 and one for Sensor2 ) to cast the obj field to the correct type.

About changing the base class

Let's talk about why it's not possible to switch the base class and why it would be inadvisable even if you could.

Think of your class as a normal struct containing fields, plus a number of functions operating on a variable of that struct type, named this .

If you inherit from Sensor1 , the struct for Camera would contain all the fields from Sensor1 and all the fields from Camera . For argument's sake, let's say it all adds up to 42 bytes of memory. And let's say combining the fields from Sensor2 with the fields from Camera adds up to 60 bytes.

Clearly, if you then dynamically change the base type, your memory size should change, but the allocation was already done by the time you enter the constructor. So if you could switch base types from Sensor1 to Sensor2 at the time, you would suddenly have 18 bytes too few and updating any of those would overwrite memory that is possibly allocated to something else. That's a disaster waiting to happen.

And so we use patterns like Strategy , as I showed here. It's easier to reason about, simple to implement, widely understood and safe.

To keep the function calls out of the Camera class, you can delegate the same task to another class, say SensorOperator . Make the Camera object composed of Sensor object. Now, in case any new class, say "Mobile", comes in which can have the same sensors, then we can use the same strategy with it.

template <typename T>
class SensorOperator : public Sensor {
private:
    T *t;
public:
    void setResolution(int w, int h) {
        t->setResolution(w, h);
    }
    void changeMode(int mode) { t->changeMode(mode); }
};
class Camera {
    public:
        Camera(bool flag) {
            //Change base class to either Sensor1 or Sensor2 which inherits from common base class Sensor
            if (flag) sensor = new SensorOperator<Sensor1>();
            else sensor = new SensorOperator<Sensor2>();

        }
        ~Camera() {}
    private:
        Sensor *sensor;
};

I would've preferred to implement the Sensor class as an abstract class. Also, prefer composition over inheritance in case of Camera class as the Camera might be many things other than just being a Sensor .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM