多态性:static_cast 的这种(潜在密集型)使用是致命的吗?

Polymorphism: is this (potentially intensive) use of static_cast a fatality?

这里是上下文:A Model 有一个(指向)Parameter 和一个 outputModelParameter 是抽象的 classes。我们使用Model*类型的指针来操作Model的各种派生(具体)classes,其指向Parameter的指针动态指向各种派生(具体)classes of Parameter.

这里以classes 的简化版本为例。我知道 new 应该避免或至少在 delete 之后,但我省略了偏离主题的代码行(例如析构函数)。

// Abstract classes
class Parameter {
public:
    virtual void reinitialize() = 0;
};

class Model{
public:
    Model(Parameter *argt){ ptr_param = argt; }
    virtual void computeModelOutput() = 0;
    double output;
    Parameter *ptr_param;
};

// Concrete classes
class ACertainKindOfParameter : public Parameter{
public:
    ACertainKindOfParameter(int argt){ value = argt; }
    virtual void reinitialize(){ value = 1; }
    int value;
};

class ACertainKindOfModel : public Model{
public:
    ACertainKindOfModel(int argt) : Model(new ACertainKindOfParameter(argt)){}
    virtual void computeModelOutput(){
        output = 10.0 + (double)(static_cast<ACertainKindOfParameter*>(ptr_param)->value);
    }
};

int main(){
    ACertainKindOfModel myModel{5};
    Model *ptr_model = &myModel;
    ptr_model->computeModelOutput();
    std::cout << ptr_model->output << std::endl; // 15
}

这段代码中令我困扰的是 ACertainKindOfModel 无法直接访问 value,所以我显然需要使用 static_cast。一个真正的 Model 当然会有一个矢量,例如50 Parameters,不仅仅是一个,所以这意味着每次计算 output 时需要 50 static_cast(或依赖于参数的任何其他操作)。这对我来说不是一个好的做法,但我可能是错的。您看到设计中的任何缺陷了吗?

注意:我曾考虑过将 Parameter 设为 class 模板,但它似乎不是一个有效的选项,因为 Parameter 的方法在不同类型的value 被考虑。在上面的简单示例中,valueint 类型,但在从 Parameter 派生的另一个 class 中,它可能是用户定义的类型,例如Color 只有三个可能的值 RGB,而 reinitialize() 将与 value = 1 大不相同。 Parameter 中的虚拟 getter() 会很好,但也不起作用,因为重新定义中的 return 类型冲突。

有几种方法可以使它更清洁。如果 Model 不需要访问 ptr_param,您可以将其从 Model 中删除并将其存储在每个派生的 class 中,并使用正确的类型。

或者您可以将 static_cast 封装在每个模型中的 getter 函数中 class:

ACertainKindOfParameter *getParam() const { return static_cast<ACertainKindOfParameter *>(ptr_param); }

您可以结合使用这两种技术。在派生模型 class 中定义参数,并使用协变 return 类型以允许基础 Model class 访问。在 Model 内声明一个 getter:

virtual Parameter *getParam() const = 0;

然后,在每个模型中,声明一个协变覆盖:

virtual ACertainKindOfParameter *getParam() const override { return ptr_param; }

假定 ptr_param 在 ACertainKindOfModel 内声明。如果不是,则需要如上所述应用 static_cast

或者您可以将 static_cast 的结果保存在 compute 函数中以避免多次使用它。