实例化派生的 class 只有一次糟糕的 OOP?

Is instantiating a derived class only once bad OOP?

我有一个 class 结构,它打算只让我派生的 classes 每个只实例化一次。在我看来,这就像糟糕的 OOP,因为多个实例将是相同的并且毫无用处,所以我应该替换它吗?

上下文: 我正在为计算器应用程序构建基础。我有一个 Operator class MultiplicationAddition 等继承自。我使用 Operator 作为抽象基础 class,然后 "Calculator" 包含一个 Operator* 的多态容器,支持一个操作实例,因此它可以调用 evaluate 只需匹配 ID 即可在 Operator 上使用。

class Operator {
public:
    virtual int evaluate(int left, int right) = 0;

protected:
    const char ID;
    const int precedence;
};

class Multiplication : public Operator {
public:
    Multiplication() {
        ID = '*';
        precedence = 2;
    }
    virtual int evaluate(int left, int right) {
        return left * right;
    }
};

class Addition : public Operator {
public:
    Addition() {
        ID = '+';
        precedence = 1;
    }
    virtual int evaluate(int left, int right) {
        return left + right;
    }
};

// etc.

此外,我有点担心如何初始化常量,但这不是我的主要问题。

这听起来是个不错的选择 std::function:

class Operator{
    public: //just for demonstration
    const char ID;
    const int precedence;
    std::function<int(int,int)> func;
}

//in main:
Operator Multiplication{
    '*',
    2,
    [](int a, int b){return a*b;}
};

这里的想法是这样的:

使 Operator 成为存储 std::function 或函数指针的 class。然后创建 class 的加法、乘法等实例,并将每个实例传递给自己的 std::function(这里我使用了 lambda,但您也可以使用普通函数)。当然这只有在所有函数的签名都相同的情况下才有效,但从你的例子看来它们是相同的。

您在评论中说:

Well I was concerned, because it seems like if I am defining an object, it should be a thing that has data associated with each instance. Here, every instance would be identical, which worries me, but I couldn't see any other way since I needed to change implementation of evaluate.

是的,每个对象的数据都是相同的。这是一个很好的观察。当每个对象的数据相同时,最好将它们变成 static 成员数据 and/or 通过函数提供对它们的访问,virtual 在适当的时候使用函数。

这是您发布的代码的一个版本,它删除了成员数据并提供了 virtual 函数来访问它们。这也避免了对显式构造函数的需求。

class Operator {
   public:
      virtual int evaluate(int left, int right) = 0;
      virtual char getID() const = 0;
      virtual int getPrecedence() const = 0;
};

class Multiplication : Operator {
   public:
      virtual char getID() const
      {
         return '*';
      }

      virtual int getPrecedence() const
      {
         return 2;
      }

      virtual int evaluate(int left, int right) {
         return left * right;
      }
};

class Addition : Operator {
   public:
      virtual char getID() const
      {
         return '+';
      }

      virtual int getPrecedence() const
      {
         return 1;
      }
      virtual int evaluate(int left, int right) {
         return left + right;
      }
};