多态性:static_cast 的这种(潜在密集型)使用是致命的吗?
Polymorphism: is this (potentially intensive) use of static_cast a fatality?
这里是上下文:A Model
有一个(指向)Parameter
和一个 output
。 Model
和 Parameter
是抽象的 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 Parameter
s,不仅仅是一个,所以这意味着每次计算 output
时需要 50 static_cast
(或依赖于参数的任何其他操作)。这对我来说不是一个好的做法,但我可能是错的。您看到设计中的任何缺陷了吗?
注意:我曾考虑过将 Parameter
设为 class 模板,但它似乎不是一个有效的选项,因为 Parameter
的方法在不同类型的value
被考虑。在上面的简单示例中,value
是 int
类型,但在从 Parameter
派生的另一个 class 中,它可能是用户定义的类型,例如Color
只有三个可能的值 R
、G
和 B
,而 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
函数中以避免多次使用它。
这里是上下文:A Model
有一个(指向)Parameter
和一个 output
。 Model
和 Parameter
是抽象的 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 Parameter
s,不仅仅是一个,所以这意味着每次计算 output
时需要 50 static_cast
(或依赖于参数的任何其他操作)。这对我来说不是一个好的做法,但我可能是错的。您看到设计中的任何缺陷了吗?
注意:我曾考虑过将 Parameter
设为 class 模板,但它似乎不是一个有效的选项,因为 Parameter
的方法在不同类型的value
被考虑。在上面的简单示例中,value
是 int
类型,但在从 Parameter
派生的另一个 class 中,它可能是用户定义的类型,例如Color
只有三个可能的值 R
、G
和 B
,而 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
函数中以避免多次使用它。