在运行时选择派生类并运行唯一的类方法

问题描述

是否可以在运行时选择派生类,然后执行具有不同参数编号/类型的方法?例如,我们有基类 Fruit

class Fruit{
    public:
        int weight;
        Fruit(int);
};

Fruit::Fruit(int w) : weight(w){};

带有派生类 AppleOrange

class Apple : public Fruit {
    public:
        void eat(int);
        Apple(int);
};

Apple::Apple(int w) : Fruit(w){};

void Apple::eat(int amount){
    weight -= amount;
};
class Orange : public Fruit {
    public:
        void eat(int,bool);
        Orange(int);
};

Orange::Orange(int w) : Fruit(w){};

void Orange::eat(int amount,bool peel){
    if (peel){
         weight /= 10;
    }
    weight -= amount;
};

它们都有 eat 方法,但参数不同。如何选择在运行时创建哪个派生类然后执行 eat

int main(){
    // read input i.e. (apple,5) or (orange,2,true)
    // create either apple or orange 
    // eat it
}

解决方法

使用类似于 command pattern 的方法。通过构造函数传递不同的参数,并在需要时执行 eat 方法的不同实现。像这样:

class Fruit {
  public:
  int weight;
  Fruit(int);
  virtual void eat() = 0;
};

Fruit::Fruit(int w) : weight(w){};

class Apple : public Fruit {
  public:
  void eat() override;
  Apple(int,int);
  int amount;
};

Apple::Apple(int w,int a) : Fruit(w){};

void Apple::eat() { weight -= amount; };

class Orange : public Fruit {
  public:
  void eat() override;
  Orange(int,int,bool);
  int amount;
  bool peel;
};

Orange::Orange(int w,int a,bool p) : Fruit(w),amount{a},peel{p} {};

void Orange::eat() {
  if (peel) {
    weight /= 10;
  }
  weight -= amount;
};
,

多态的目标是不知道您正在访问的对象的具体细节。在这种情况下,由于 Orange 具有 peel 没有的额外 Apple 操作,因此我会采用更类似的方法:

class Peelable {
public:
    virtual void peel() = 0;
};

class Fruit {
public:
    int weight;

    Fruit(int weight) : weight(weight) {}
    virtual ~Fruit() = default;

    void eat(int amount) { weight -= amount; }
};

class Apple : public Fruit {
public:
    Apple(int weight) : Fruit(weight) {}
};

class Orange : public Fruit,public Peelable {
public:
    Orange(int weight) : Fruit(weight) {}
    void peel() override { weight /= 10; }
};

int main() {
    // read input i.e. (apple,5) or (orange,2,true)

    // create either apple or orange 
    Fruit *f = new /* Apple(5),Orange(2),... */;

    // eat it
    Peelable *p;
    if ((p = dynamic_cast<Peelable*>(f)) && shouldPeel) {
        p->peel();
    }
    f->eat();

    delete f;
}