C ++使用类似虚拟公共类

时间:2016-10-02 12:20:51

标签: c++ class

假设我有一堆像这样的继承类:

diamond

......它们都是为了制作各种多项式。类X主要是变量槽,类AB等都是virtual public X,每个都创建ont类型的多项式,类Y进行调用。除了AB之外,还可以添加任何其他类。

现在,一切正常,但是对于新添加的“虚拟公共”类,我需要重用其他类中的一些成员函数,这里来自类A内的B。我试着做出最简单的例子:

#include <iostream>
#include <cmath>
#include <functional>

// variable tank
class X
{
protected:
    // general variables
    double *m_c;
    int m_n;
    double m_w;
    // funcX related
    double m_r;
    int m_i {0};

public:
    ~X() = default;

    /* Simple bracketed root-finding. This is called from more than
     * one "virtual public" classes.
     */
    const double funcX(const double &x, const double &y,    \
                       std::function<const double(const double&, const int&)> fp,   \
                       const int &k)
    {
        double a {x}, b {y}, fmid;
        while (m_i<100)
        {
            m_r = 0.5*(a + b);
            fmid = fp(m_r, k);
            if (fabs(b-a) <= 1e-3)
                break;
            if (fmid < 0)
                b = m_r;
            else
                a = m_r;
            ++m_i;
        }
        return m_r;
    }
};

// one of the many classes that generate polynomials
class A: virtual public X
{
public:

    void funcA(const int &n)
    {
        // set order
        m_n = n;
        // calculate X::m_c[i]
        m_c = new double[m_n+1];
        for (short i=0; i<=m_n>>1; ++i)
        {
            int sgn {i%2 ? -1 : 1};
            m_c[i<<1] = sgn/((i + 1.0)*(i + 1.0));
        }
        // The polynomial is zero somewhere, use funcX() to find where.
        m_w = funcX(5.0, 0.0,   \
                    [this](const double &x, const int &n)   \
                    { return calcA(x, n); },    \
                    m_n);
    }

    // calculates the value of the polynomial of order n, at x
    const double calcA(const double &x, const int &n) const
    {
        double out {static_cast<double>(m_c[0])};
        for (short i=1; i<=n; ++i)
            out = m_c[i] + x*out;
        return out;
    }
};

class B: virtual public X
{
private:
    A m_a;  // otherwise the lambda function does not "catch" it
public:
    void funcB(const int &n)
    {
        // same as in A
        m_n = n;
        // same as in A, calculate coefficients
        m_c = new double[m_n+1];
        for (short i=0; i<=m_n; ++i)
        {
            int sgn {i%2 ? -1 : 1};
            m_c[i] = sgn/((i + 1)<<1);
        }
        /* Here I need A::calcA(). Instead of duplicating the code,
         * I want to call it through X::funcX(). The code compiles,
         * but it crashes.
         */
        m_w = funcX(0.5, 1.0,   \
                    [this](const double &x, const int &n)   \
                    { return m_a.calcA(x, n); },    \
                    m_n);
    }
    const double getW() const { return m_w; }
};

class Y: public A, public B
{
public:
    Y(const int &n, const int &i)
    {
        // call one of the "virtual public" classes through i
        switch (i)
        {
        case 1: funcA(n);    break;
        case 2: funcB(n);    break;
        }
    }
    void printC() { for (short i=0; i<=m_n; ++i) std::cout << m_c[i] << '\n'; }
    void printW() { std::cout << m_w << '\n'; }
    void printA(const double &x, const double &n) { std::cout << A::calcA(x, n) << '\n'; }
};

int main(int argc, char *argv[])
{
    int N {6};
    Y *y;
    for (short i=1; i<=2; ++i)
    {
        y = new Y(N, i);
        y->printC();
        y->printW();
        y->printA(1.2, N);
    }

    return 0;
}

班级X

X::funcX()是一种简单的根查找算法,可以在多个virtual public类(AB等中调用。 m_cm_nm_w是共享变量。

课程AB

他们的主要功能是funcA()(和funcB(),依此类推)并根据计算的顺序创建多项式(在体内,有一个for循环), X::m_n。评估多项式为A::calcA()。这需要由class B调用,或者重新定义。因为代码膨胀,我宁愿避免使用后者。对于我相当初学的水平,它看起来也不是很“专业”...

班级Y

这会根据参数virtual publici)调用任何switch/case类。

代码编译,但崩溃了。它打印的情况下。此示例指向A::funcA()作为罪魁祸首,但在原始程序中,我可以看到系数m_c[i]甚至没有使用动态内存进行初始化,就像尝试打印m_c[0]一样崩溃。我尝试在new double[]中移动A insode函数,但这不起作用。

我不知道如何制作它。这是否有意义,是否可能?如果是,怎么样?

修改:忘记添加我不能只将calcA()A移到X的顶部,因为每个多项式的评估方式都不同,就像有快捷方式一样,每一个中的变化都可以对每个多项式进行不同的优化评估。我可以使X::calcA()成为一个通用的,但是会有性能损失,我宁愿不付钱。

1 个答案:

答案 0 :(得分:4)

似乎您的问题是由设计问题引起的。当您需要使用其他类中可能意味着的方法时:

  1. 问题是&#34;单一责任&#34;原理。上课做得太多了。例如,数值方程求解算法是自足的实体,不应该是多项式的一部分。它们可以与任何多项式一起使用。
  2. 继承树存在问题。例如,应该创建一个共同的祖先,并且常见的方法应该在其中。请注意,如果您无法找到该祖先的简短且可理解的名称,那么这不是解决方案。
  3. 未正确使用继承。例如,我无法在代码中看到奇怪的虚拟方法。
  4. 让我们更接近你的榜样。您正在使用虚拟多重继承,这被认为是非常繁重的模式,通常不应使用。此外,您的代码中没有虚拟方法,因此您实际上根本不使用继承。您要么必须删除继承,要么考虑对所有类都有意义的常用方法。对于函数,这似乎是在指定点计算函数值的能力。然后移动所有代码,而不是从类中描述多项式或函数。移出数值解算器。这将允许为所有类重用它们,以支持所需的接口。完全摆脱Y课程。看来,需要使用开关和枚举来模拟虚拟方法。你不需要它,如果它们在语义上是相同的,那么将funcA和funcB重命名为func,并为不同类型的多项式做同样的事情。