Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何避免复合图案中的向下投射_C++_Design Patterns_Composite_Visitor Pattern - Fatal编程技术网

C++ 如何避免复合图案中的向下投射

C++ 如何避免复合图案中的向下投射,c++,design-patterns,composite,visitor-pattern,C++,Design Patterns,Composite,Visitor Pattern,我使用复合模式来表示a,它描述了材料的力学行为,例如,模型,与n平行的弹簧麦克斯韦元件iteslf是一个串联有阻尼器的弹簧。 机械网络是在运行时动态组成的。为此,我从一个公共基类组件派生了Spring、MaxwellElement和ParallelConnection: struct Component { virtual void add_component (Component* ) { } virtual Tensor<2> stress (const Tens

我使用复合模式来表示a,它描述了材料的力学行为,例如,模型,与n平行的弹簧麦克斯韦元件iteslf是一个串联有阻尼器的弹簧。 机械网络是在运行时动态组成的。为此,我从一个公共基类
组件
派生了
Spring
MaxwellElement
ParallelConnection

struct Component {
    virtual void add_component (Component* ) { }
    virtual Tensor<2> stress (const Tensor<2> &strain) const = 0;
    virtual ~Component () = default;
};

struct Spring : Component {    
    Tensor<2> stress (const Tensor<2> &strain) const override {return {};};
};

struct SpecialSpring : Spring {

    Tensor<1> principal_stresses (const Tensor<1> &strain_eigenvalues) const {return {};};
};

struct ParallelConnection : Component {

    void add_component (Component* c) override {components.emplace_back(c);}
    Tensor<2> stress (const Tensor<2> &strain) const override {
        Tensor<2> s; 
        for (const auto& c : components)
            s += c->stress(strain);
        return s;
    };
    std::vector<std::unique_ptr<Component>> components;
};

struct MaxwellElement : Component {

    Tensor<2> stress (const Tensor<2> &strain) const override {
        auto special_spring = dynamic_cast<SpecialSpring*>(spring.get());
        if (special_spring) {
            const auto ps = special_spring->principal_stresses (eigenvalues(strain));
            // Some cheap calculations using ps and member variables
            // of MaxwellElement, which are left out for simplicity.
            return {}; // <- meaningful result
        } else {      
            const auto s = spring->stress (strain);
            // Some expensive calculations using s and member variables
            // of MaxwellElement, which are left out for simplicity.
            return {}; // <- meaningful result
        }   
    };    

    virtual void add_component (Component* c) {
        if (!spring)
            spring.reset(dynamic_cast<Spring*>(c));
        assert (spring);
    }

    std::unique_ptr<Spring> spring;
};
实现
组件visitor
和添加
accept
方法作为家庭作业;)我希望我的目标仍然清晰。现在,基于std::variant::index()
,我可以选择正确的算法。然而,我还是觉得自己的设计很糟糕

有没有更好的方法来实现上述目标?


我当前的实现是问题本身吗?我正在处理的是XY问题吗?

如果我理解正确,似乎是这样或那样,您需要以编程的方式确定要执行哪些计算—无论是便宜的还是昂贵的—问题在于如何实现这一点

假设
张量
只是
张量
在结构上的简化表示(因为张量通常是这样的,对吗?),我会同意在
SpecialSpring
类中覆盖
应力()

  • 它会在内部调用
    特征值(应变)
  • 它将其内部计算结果概括为
    张量
    表示并返回该表示
大概是这样的:

struct Spring : Component {    
    virtual Tensor<2> stress (const Tensor<2> &strain) const override {return {};};
};

struct SpecialSpring : Spring {
    Tensor<1> principal_stresses (const Tensor<1> &strain_eigenvalues) const {return {};};

    virtual Tensor<2> stress (const Tensor<2> &strain) const override {
        Tensor<1> t1 = principal_stress(eigenvalues(strain));
        Tensor<2> t2 = some_function_to_generalize_T1_to_T2(t1);
        return t2;
    };
};
struct-Spring:组件{
虚张量应力(常数张量&应变)常数覆盖{return{};};
};
结构特殊弹簧:弹簧{
张量主应力(常数张量&应变特征值)常数{return{};};
虚拟张量应力(常数张量和应变)常数覆盖{
张量t1=主应力(本征值(应变));
张量t2=一些函数,将T1推广到t2(T1);
返回t2;
};
};
然后,在
MaxwellElement::stress()
中,您只需调用
spring->应力(应变)
,然后检查返回的
张量是否足够简单,可以进行廉价的计算


当然,使用这种方法,还有一个新问题-额外的计算(将
张量的表示形式更改为
张量,然后在返回
张量后基本上做相反的事情)是否更好(性能方面)比动态的演员阵容听起来有点像解决问题的方法。他们早已被提议用于C++,但从未将其应用到语言中。看起来模式匹配将提供类似的功能,但具有不同的属性。@dyp是的,您是对的。在这种特殊情况下,多方法会很好。我没听说过模式匹配。就是你指的。是的,在某种程度上。或者类似的。想法是定义两种类型的模式(哪个类派生自组件,哪个Spring类型)。multimethods和pattern matching都不完全适合您的问题,因为在您的情况下,spring隐藏在组件内部,而且
Component::stress
的调用者无法访问它进行分派;然而,我认为这里的例子是不完整的。不知何故,
SpringVisitor
必须传递到
组件中,也就是说,您似乎缺少Visitor模式中的
accept()
方法。推送实现总是可以实现的,但它会受到紧耦合的影响。例如,在弹簧类中,
张量应力(常数张量&应变)常数覆盖;麦克斯韦(/*任何必要的参数*/)=0的虚拟张量应力
maxwell的
应力\u优化\u应能在普通字符串和特殊字符串上运行,但在特殊字符串上使用便宜的计算。+1,因为这种方法可能对其他方法有所帮助。然而,这在我的情况下不起作用。一阶张量
张量
是向量,二阶张量
张量
是矩阵。也就是说,
张量
可以存储在
张量
中。您的解决方案的问题是,
压力(…)
的原始结果将丢失。当
SpecialSpring
ParallelConnection
中的一个组件时,它需要调用原始的
应力(…)
函数。我目前的方法困扰我的并不是
动态转换的性能损失(即使是便宜的计算也比这昂贵得多)更重要的是我感到沮丧。对我来说,这是我的代码设计选择不佳的标志。因此,访问者模式进行了调度。也许拥有
MaxwellElement
SpecialMaxwellElement
,将是一个解决方案。但是谢谢,我真的很感谢你的帮助。
struct Spring : Component {    
    virtual Tensor<2> stress (const Tensor<2> &strain) const override {return {};};
};

struct SpecialSpring : Spring {
    Tensor<1> principal_stresses (const Tensor<1> &strain_eigenvalues) const {return {};};

    virtual Tensor<2> stress (const Tensor<2> &strain) const override {
        Tensor<1> t1 = principal_stress(eigenvalues(strain));
        Tensor<2> t2 = some_function_to_generalize_T1_to_T2(t1);
        return t2;
    };
};