2016-10-02 71 views
4

假設我有一大堆的繼承類的這樣的使用成員函數:C++從類似的虛擬公共類

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_c,m_n,m_w是共享變量。

AB

它們的主要功能是funcA()(和funcB(),等等),並創建多項式(在體內,有一個for循環),根據計算出的順序,X::m_n上。評估多項式爲A::calcA()。這也需要由class B調用,或者重新定義。由於代碼膨脹,我寧願避免後者。它也不會找我相當初級水平非常「專業」 ......

Y

這就要求任何根據的說法i(該switch/case)的virtual public類。

該代碼編譯,但崩潰。它打印案件。這個例子指向A::funcA()作爲罪魁禍首,但在原始程序中,我可以看到係數m_c[i]甚至沒有使用動態內存進行初始化,如試圖打印出m_c[0]崩潰。我試圖移動new double[] insode函數A,但這不起作用。

我不知道該怎麼做。這是否有意義,有可能嗎?如果是,如何?


編輯:忘了補充一點,我不能隨便動calcA()A頂端,在X,因爲每一個多項式不同的評估,因爲有捷徑,變化,在每一個,使得它可能對每個多項式進行不同的優化評估。我可以讓X::calcA()成爲一個普遍的,但會有一個表現懲罰,我寧願不支付。

+1

'y = new Y(N,i);' - 您正在循環中創建內存泄漏。 – PaulMcKenzie

+0

@PaulMcKenzie我現在看到了,我做了'Y y {N,1}',然後使用'y.bla',現在它工作。但是,在我的程序中,我甚至沒有到達那裏。 'm_c []'數組沒有被初始化。由於已有超過20個文件,因此我不能只發布所有內容,而簡化將意味着至少有5個文件。如果我顯示錯誤會有幫助嗎? –

+0

請使用'std :: vector'而不是原始指針(爲什麼除了明顯的使用其他所有東西?)。一旦你這樣做,你會發現'm_c'的大小爲0,但是你在這裏訪問它:'double out {static_cast (m_c [0])};'。 [看到這裏](http://ideone.com/TcjUPx) – PaulMcKenzie

回答

4

看來你的問題是由設計問題引起的。當您需要使用其他類的方法時,這可能意味着:

  1. 這是「單一責任」原則的問題。班級確實太多了。例如數值方程求解算法是自給自足的實體,不應該是多項式的一部分。他們可以使用任何多項式。
  2. 繼承樹存在問題。例如,應該創建一個共同的祖先,並且應該有共同的方法。請注意,如果您無法找到該祖先的簡短和可理解的名稱,那麼這不是解決方案。
  3. 繼承使用不當。例如,我看不到你的代碼中的虛擬方法很奇怪。

讓我們接近你的例子。您正在使用被認爲是非常繁重的虛擬多重繼承,通常不應該使用它。而且,你的代碼中沒有虛方法,所以你實際上根本不使用繼承。你或者必須放棄繼承,或者考慮對所有類都有意義的常用方法。對於函數來說,這似乎是在指定點計算函數值的能力。然後移動所有代碼,即不從類中描述多項式或函數。移出數值求解器。這將允許爲所有類重用它們,這些類支持所需的接口。完全擺脫Y類。看來,需要用開關和枚舉模擬虛擬方法。你不需要它,重命名funcA和funcB只是爲了func,如果它們在語義上是相同的並且對不同類型的多項式做同樣的事情。

+0

我從繼承開始,我計劃在'Y'裏面用'switch/case'調用類'A','B'等中的構造函數(它也處理輸出到屏幕結果等等),但是我不能不這樣做,所以我切換到簡單的成員函數,如'funcA()'。這些類本身被製作得很簡單,因爲它們只創建多項式的類型,就是這樣。類'X'包含變量,通用於'A','B'等,而'Y'類對所有東西都非常適用,打印,計算和評估,它本意是成爲整個事物的「控制面板」。儘管如此,你是對的,它是混亂的,並且變得更糟...... –

+0

當Y類實現類A時,意味着Y是A的一種特殊類型,並且可以做所有事情A可以。所以如果Y從A和B繼承,那麼它同時是A和B.在你的例子中,繼承使用「顛倒」。所有常用功能必須位於基礎中。它們可能是抽象的(具體實現由祖先提供),但它們必須在基礎中定義。 –

+0

我試過這樣做,查找算法在'X'中,在頂部,供需要它的任何人使用。假設它是這樣的:我需要打印出一個多項式並在一定範圍內進行評估。 'Y'這樣做,但是哪一個? 'i'是選擇,它稱爲合適的多項式類,它只創建多邊形。這些術語對於所有poly類都是通用的,並且存儲在'X'中。所以'Y'調用'A'(如果'i = 1'),它使用'X'中的係數根據'A'的規則計算多邊形。如果我需要'B',我叫'B',它使用'X'中的coeffs。這將是一個粗暴的解釋。 –