以下是上下文:Model
有一个(指针)Parameter
和output
。 Model
和Parameter
是抽象类。我们使用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
当然会有一个例如50 Parameter
s,而不仅仅是一个,因此每次计算static_cast
(或依赖参数的任何其他操作)时,这意味着50 output
。对我来说这看起来不是一个好习惯,但我可能错了。你看到设计中有任何缺陷吗?
注意:我考虑过将Parameter
作为一个类模板,但它似乎不是一个有效的选项,因为Parameter
的方法在value
的不同类型时有很大不同考虑。在上面的简单示例中,value
的类型为int
,但在另一个派生自Parameter
的类中,它可以是用户定义的类型,例如只有三个可能值Color
,R
和G
以及B
的{{1}}与reinitialize()
非常不同。 value = 1
中的虚拟getter()
会很棒,但也不会有效,因为重新定义中的返回类型存在冲突。
答案 0 :(得分:3)
有几种方法可以使它更清洁。如果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
函数中,以避免多次使用它。