c++虛擬函式實現計算表示式子

Hhy*發表於2020-11-25

c++虛擬函式實現計算表示式

簡單的運算直接用運算子計算當然是簡單的

但是如果在一個表示式中,每一步的運算都很複雜呢?

並且還需要隨時新增複雜的表示式呢?

直接用運算子來構造就顯得有些冗雜了吧,也很不方便修改。

於是我們可以構造虛擬函式來解決這樣的問題

為了方便表達,我們這裡舉一個這樣的例子:

( ( 1 + 2 ) × 3 + 4 ) ÷ 6 \left( \left( 1+2\right) \times 3+4\right) \div 6 ((1+2)×3+4)÷6

雖然比較簡單,但是能體現大致的思想。

我們把它寫成樹,每個root都是一個運算方法。

如圖所示:

樹形圖

每一個節點的運算引數要麼是常數(此處我們叫做 TerminalExpression),要麼是表示式(可能是 AddExpression 也有可能是 Mutiplyexpression)。

由此我們想到可以用一個統一的函式去返回他們的值:

getvalue()

也就是說每一個的節點(運算)都可以當作一個派生類,而他們的 getvalue() 函式由該派生類中定義的兩個基類指標決定(由於基類指標可以指向派生類的物件!),派生類的物件型別由我們自己去輸入。

說到這裡可能有些雲裡霧裡,下面我們給出程式碼會更直觀一些:

#include<iostream>
#include<algorithm>

using namespace std;


class expression
{
public:
    float value;
    expression()
    {
        value = 0;
    }
    virtual float getvalue() = 0;
};

//所有的派生類(表示式)都有一個返回float型的getvalue()返回該基類派生類的value
class TerminalExpression: public expression
{
public:
    virtual float getvalue()
    {
        return value;
    }
};

class AddExpression: public expression
{
public:
    expression* l;                                  //基類的指標可以new派生類的物件!!!
    expression* r;
    virtual float getvalue()
    {
        value = l->getvalue() + r->getvalue();
        return value;
    }
};

class MultiplyExpression: public expression
{
public:
    expression* l;
    expression* r;
    virtual float getvalue()
    {
        value = l->getvalue() * r->getvalue();
        return value;
    }
};

class DivisionExpression: public expression
{
public:
    expression* l;
    expression* r;
    virtual float getvalue()
    {
        value = l->getvalue() / r->getvalue();
        return value;
    }
};

//((1 + 2)*3 + 4)/6 = 2.16667
int main()
{
    AddExpression *p = new AddExpression;
    p->l = new TerminalExpression;
    p->l->value = 1;
    p->r = new TerminalExpression;
    p->r->value = 2;                                    //左右兩側均為terminal賦值

    MultiplyExpression *q = new MultiplyExpression;
    q->l = new AddExpression;
    q->l = p;                                           //左側的值為表示式p
    q->r = new TerminalExpression;
    q->r->value = 3;

    AddExpression *n = new AddExpression;
    n->l = new MultiplyExpression;
    n->l = q;                                           //左側的值為表示式q
    n->r = new TerminalExpression;
    n->r->value = 4;

    DivisionExpression *d = new DivisionExpression;
    d->l = new AddExpression;
    d->l = n;                                           //左側的值表示式為n
    d->r = new TerminalExpression;
    d->r->value = 6;

    cout<<d->getvalue()<<endl;
    return 0;
}

在程式碼中可以直觀地看到,每一個運算是一個派生類,在main函式中是對其運算引數的賦值。

因此在main函式中,我們只需對每個運算的左引數和右引數進行賦值即可。

因此通過虛擬函式,我們可以輕易地增加運算,新增一個派生類即可,體現了C++對增添開放對修改封閉的特點。

其中最妙的地方在於基類指標可以new出派生類的物件,才能使該方法實現。

希望能和大家多多交流!

相關文章