假设我们有一个抽象课 Element 从哪个课程 TriangleQuadrilateral 是从。

假设这些类是与取决于元素形状的插值方法结合使用的。因此,基本上我们创建了一个抽象类 InterpolationElement 我们得出的 InterpolationTriangleInterpolationQuadrilateral.

然后,将插值功能包括在 TriangleQuadrilateral 课程,我们在类中添加一个const-Reference数据成员 Element 类型 InterpolationElement, , 那是:

class Element
{
public:
    Element(const InterpolationElement& interp);

    const InterpolationElement& getInterpolation() const;

private:
    const InterpolationElement& interpolation;
};

然后,我们创建一个方法(如Scott Meyers所述,有效的C ++),可以实现类的本地静态对象 InterpolationTriangle 作为

const InterpolationTriangle& getInterpolationTriangle()
{
    static InterpolationTriangle interpolationTriangle;

    return interpolationTriangle;
}

这样的课 Triangle 可以像:

class Triangle : public Element
{
public:
    Triangle() : Element( getInterpolationTriangle() ) {}
};

这是我的问题:为了在我的班级中纳入插值方法,这种方法是否正确 Element?这是在专业场景中使用的吗?

我可以直接在类上实现所有插值方法 Element (纯虚拟),并在派生类中覆盖它们 TriangleQuadrilateral. 。但是,在我看来,这种方法似乎很麻烦,因为每次我需要改进或实施新的插值功能时,我都必须在这些课程上这样做。此外,使用这种方法会变得越来越大(许多方法)。

我想听听您的一些技巧和评论

提前致谢。


额外细节:

class InterpolationElement
{
public:
    InterpolationElement();

    virtual double interpolationMethod1(...) = 0;
                      :
    virtual double interpolationMethodN(...) = 0;
}

class InterpolationTriangle : public InterpolationElement
{
public:
    InterpolationTriangle () {}

    virtual double interpolationMethod1(...) { // interpolation for triangle }
                      :
    virtual double interpolationMethodN(...) { // interpolation for triangle }
}

class InterpolationQuadrilateral : public InterpolationElement
{
public:
    InterpolationTriangle () {}

    virtual double interpolationMethod1(...) { // interpolation for quadrilateral}
                      :
    virtual double interpolationMethod1(...) { // interpolation for quadrilateral}
}
有帮助吗?

解决方案

这些类与插值结合使用 方法. 。为什么这些方法需要在单例对象中?这里的单身人看起来很成问题。

class Element
{
public:
    virtual double interpolationMethod1(...) = 0;
                  :
    virtual double interpolationMethodN(...) = 0;

};

class Triangle : public Element
{
public:
    virtual double interpolationMethod1(...) { // interpolation for triangle }
                  :
    virtual double interpolationMethodN(...) { // interpolation for triangle }
}

另外,欢迎来到!

其他提示

这让人想起我回答的问题 这里. 。关于数据容器和策略的分离的相同想法。

您的建议存在一个小问题:您已在基类中添加了与插值相关的方法,并且您已经更改了构造函数...

因此,首先,如果您想这样做,这就是您应该做的:

class Element
{
public:

private:
  // similar signature to a `clone` method
  virtual InterpolationElement* interpolation() const = 0;
};

class Triangle
{
public:

private:
  virtual InterpolationTriangle* interpolation() const
  {
    return new InterpolationTriangle();
  }
};

这里有2个优势:

  • 不再需要更改每个派生对象的构造函数
  • 策略对象不再 const, ,这使其可以在计算过程中保持状态……就像对当前对象插值的引用一样。

但是,这仍然需要更改 Element 类及其每个派生类。不打扰你;)吗?

好吧,现在是时候(一次)呼吁设计模式: Visitor.

这与策略想法有所不同,依靠双重调度来正常工作。但是,它允许您调整 ElementS一次(有一个 accept 方法),然后添加尽可能多的操作。那太好了。

您总是可以用模板弄乱一点。首先,我们有顶级班级。

class Element {
    public:
        virtual void calculate() const = 0;
};

...但是然后,我们在层次结构中间也有一个类,这实际上是一个模板。模板不能成为顶级类,因为具有不同参数的模板是不同的类。这个想法是,我们将插值类作为元素的类型参数。

template <typename Interpolation>
class Element_Impl : public Element {
    protected:
        Interpolation m_interpolation;
};

和插值类。注意,他们不是兄弟姐妹,因为他们不需要。

class InterpolationTriangle {
    public:
        double interpolate(double a, double b) const {
            std::cout << "interpolation triangle" << std::endl;
        }
};
class InterpolationQuadrilateral {
    public:
        double interpolate(double a, double b) const {
            std::cout << "interpolation quadrilateral" << std::endl;
        }
};

最后,真实元素和小主要过程。

class Triangle : public Element_Impl<InterpolationTriangle> {
    public:
        void calculate() const {
            m_interpolation.interpolate(1.0, 2.0);
        }
};
class Quadrilateral : public Element_Impl<InterpolationQuadrilateral> {
    public:
        void calculate() const {
            m_interpolation.interpolate(2.0, 3.0);
        }
};
int main() {
    const Element &a = Triangle();
    const Element &b = Quadrilateral();
    a.calculate();
    b.calculate();
}

概括:

  • 如果需要,您可以轻松地为每个元素切换插值类。
  • 在Matthieu的示例中,没有双重vtable访问(首先是计算元素的计算,然后是Interpolationelement的插曲方法)。每个元素在编译时间都知道它正在使用的插值类。
  • element_impl是一个丑陋的位,但它使我们脱离了复型。您可以通过实施插值方法包装器进一步扩展它
  • http://en.wikipedia.org/wiki/curiye_recurring_template_pattern

一种方法是使用静态方法,并在element_impl中定义包装器 - 仅在一个地方。

class Element {
    public:
        virtual void calculate() const = 0;
};

template <typename Interpolation>
class Element_Impl : public Element {
    protected:
        void interpolate(double, double) const {
            Interpolation::interpolate(1, 1);
        }
};

class InterpolationTriangle {
    public:
        static double interpolate(double a, double b) {
            std::cout << "interpolation triangle" << std::endl;
        }
};

class InterpolationQuadrilateral {
    public:
        static double interpolate(double a, double b) {
            std::cout << "interpolation quadrilateral" << std::endl;
        }
};

class Triangle : public Element_Impl<InterpolationTriangle> {
    public:
         void calculate() const {
            interpolate(1.0, 2.0);
        }
};

class Quadrilateral : public Element_Impl<InterpolationQuadrilateral> {
    public:
        void calculate() const {
            interpolate(2.0, 3.0);
        }
};

int main() {
    const Element &a = Triangle();
    const Element &b = Quadrilateral();

    a.calculate();
    b.calculate();
}

我首先想到的是 GOF设计模式访问者

据我了解您的问题,这种模式可以准确地解决此问题。

每个访问者对象都定义一种插值技术或用于应用于对象的算法。

因此,元素类在每个新功能时根本不会增长。一旦到位,访问者模式就可以丰富功能,而无需触摸基类定义。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top