2017-09-01 34 views
3

这是上下文:A Model有一个(指向)ParameteroutputModelParameter是抽象类。我们使用Model*类型的指针来操纵Model的各种派生(具体)类,其指针Parameter动态指向各种衍生(具体)类Parameter的实例。多态性:这是(可能密集型)使用static_cast致命吗?

下面是一个简化版本的类作为例子。我知道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 
} 

让我困扰的这个代码是ACertainKindOfModelvalue不能直接访问,所以我显然需要使用static_cast。真正的Model当然会具有例如每次计算output(或任何其他依赖于参数的动作)时,这将意味着50 static_cast。这对我来说不太好,但我可能是错的。你看到设计中的缺陷吗?

注:我觉得做Parameter类模板,但它似乎并没有一个有效的选择,因为Parameter的方法时,不同类型的value被认为是深有所不同。在上面的简单示例中,value类型为int,但是在从Parameter派生的另一类中,它可以是用户定义的类型,例如, Color只有三个可能的值R,GBreinitialize()会与value = 1有很大不同。 Parameter中的虚拟getter()会很好,但是也不起作用,因为重定义中的返回类型是冲突的。

+1

你打算怎么处理价值?如果是计算,请查看[访问者模式](https://en.wikipedia。org/wiki/Visitor_pattern),所以没有其他类必须知道它的价值。如果是显示,可以考虑添加一个虚拟getter,它以'string'的形式返回中性形式的值。 – user4581301

+1

@ user4581301事实上,'value'主要用于计算,如我写的那段代码所示,也可能出现在if(value == R)等条件中,等等(特别是value是不是数字)。感谢您对Visitor模式的建议。 – Georg

+0

*“我知道应该避免新的”*。所以使用智能指针:甚至更少的代码行。 – Jarod42

回答

3

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

或者你可以封装在每个模型类中的一个getter函数的static_cast

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函数中,以避免多次使用它。

+0

我个人的结论是:我尝试了无数的事情,主要归结为最初的'static_cast'。使'参数'模板类几乎工作,但最终失败,因为模板参数演绎[不适用于声明指针](https://stackoverflow.com/questions/46085683/)。 – Georg