C++基礎::類設計的幾大原則

Inside_Zhang發表於2015-11-10
  • 類圍繞成員變數進行設計,建構函式圍繞成員變數構建類,成員函式圍繞成員變數展開
    總之,在類的宣告與實現中,成員變數居於中心的位置。

  • -

普通成員函式與虛擬函式

在一個抽象基類的內部可以有三種形式成員函式:

  • 普通成員函式
    所有派生類共享的函式實現,可以不給出實現(其實這樣做沒有意義),但當呼叫時自然會發生解析錯誤。
  • 虛擬函式
    必須給出實現,否則子類無法進行函式的重寫。不同的子類可對其進行部分重寫,根據需求。
  • 純虛擬函式
    全部子類如果想成為能夠例項化物件的類,必須實現父類的全部純虛擬函式,否則子類仍是抽象類無法例項化物件。


這裡寫圖片描述

class Base
{
public:
    void foo(){}            // 普通函式
    virtual void fooA();   
            // 虛擬函式,交由DerivedA 實現
    {
        throw std::exception("cannot be called");
        // 拋異常的目的是為了禁止DerivedB物件試圖去呼叫(設計上)只能交由DerivedA物件呼叫的函式時
    }
    virtual void fooB();
            // 虛擬函式,交由DerivedB實現
    {
        throw std::exception("cannot be called")
        // 拋異常的目的是為了禁止DerivedA物件試圖去呼叫(設計上)只能交由DerivedB物件呼叫的函式時
    }
    virtual void f() = 0;
            // 純虛擬函式
}
class DerivedA :public Base
{
public:
    void fooA() 
    { cout << "DerivedA::fooA()" << endl;}
    void f(){}
}
class DerivedB :public Base
{
public:
    void fooB() 
    { cout << "DerivedB::fooB()" << endl;}
    void f() {}
}

int main(int, char**)
{
    DerivedA da;
    DerivedB db;
    da.foo();
    db.foo();              // 呼叫父類的非虛成員函式

    da.fooB();             // 拋異常
    da.fooA();             // 多型,呼叫DerivedA的實現

    db.fooA();             // 拋異常,
    db.fooB();             // 多型,呼叫DerivedB的實現

    Base* b = new DerivedA;
    b->fooA();             // 多型
    b->fooB();             // 拋異常

    b = new DerivedB;
    b->fooB();             // 多型
    b->fooA();             // 拋異常

    return 0;
}

使用UML類圖,

即可以在設計好UML類圖的前提之下進行程式碼的編寫,也可邊寫程式碼,邊設計類圖。

從成員變數開始一個類的設計

成員函式圍繞成員變數進行展開;

多個過載版本

可以有不同的過載版本(客戶端呼叫的方便),實現時然後相互呼叫(為了編寫程式碼的便捷)

這種過載不僅對於類的成員函式之間是如此,不同的全域性函式也是如此,不妨以STL的演算法中的sort為例進行展示:

從最終客戶端的呼叫方式倒推類及其成員函式的設計

virtual 函式 幾乎等同於需要在派生類進行重寫的函式

相關文章