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

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

本文关键字:cast static 使用 这种 多态性      更新时间:2023-10-16

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

下面是类的简化版本作为示例。我知道应该避免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当然会有一个例如 50Parameters 的向量,而不仅仅是一个,所以这意味着每次计算output时 50static_cast(或任何其他依赖于参数的操作)。这对我来说似乎不是一个好的做法,但我可能是错的。你看到设计有什么缺陷吗?

注意:我想过将Parameter作为类模板,但这似乎不是一个有效的选项,因为当考虑不同类型的value时,Parameter的方法差异很大。在上面的简单示例中,value的类型为int,但在从Parameter派生的另一个类中,它可以是用户定义的类型,例如 只有三个可能值RGBColorreinitialize()value = 1非常不同。Parameter中的虚拟getter()会很好,但也不会起作用,因为重新定义中的返回类型冲突。

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

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

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

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

virtual Parameter *getParam() const = 0;

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

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

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

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