1. 程式人生 > >C++:如何正確的定義一個介面類

C++:如何正確的定義一個介面類

C++中如何定義介面類?

首先給介面類下了定義:介面類應該是隻提供方法宣告,而自身不提供方法定義的抽象類。介面類自身不能例項化,介面類的方法定義/實現只能由介面類的子類來完成。

而對於C++,其介面類一般具有以下特徵:

1.最好不要有成員變數,但可以有靜態常量(static const或enum)
2.要有純虛介面方法
3.要有虛解構函式,並提供預設實現
4.不要宣告建構函式

如下就是一個最簡單的例子:

class Testable
{
public:
    static const int START = 1;  // #1
    static const int STOP = 2;

    virtual void test() = 0;  // #2: 介面方法

    virtual ~Testable() {};   // #3: 從C++11開始可以: virtual ~Testable() = default;
}

#1.

如果成員變數,尤其是可變的成員變數,定義在介面中,等於是把實現細節暴露出來了,不符合介面定義的要求,所以一般不在介面中定義可變的成員變數。
而常量可以定義在介面中,因為有時介面需要返回狀態,而這些狀態可以定義成常量放在介面中。

#2.

由於不能讓介面類自身能夠例項化,並且需要子類必須實現介面暴露的方法,所以介面方法都要宣告成純虛擬函式。
宣告成純虛擬函式意味著介面類自身不需要提供方法的定義,方法的定義需要由介面類的子類提供,並且介面類自身也因此變成了抽象類而不能被例項化。

#3.

a). 在使用介面類的指標訪問介面類的子類的例項時,當對介面類的指標做delete時,如果介面類的解構函式不是虛解構函式的話,將只會呼叫介面類的解構函式,介面類的子類的解構函式將不會被呼叫,記憶體洩露將會產生,所以介面類的解構函式必須定義成虛解構函式。
b).

如果介面類的解構函式不提供預設實現,即如果介面類的解構函式是純虛解構函式的話,介面類的子類將被迫必須提供解構函式的實現,這樣對介面類的子類不友好。
c). 在C++11中也可以用:  virtual ~Testable() = default; 替代 virtual ~Testable() {};

#4.

不要顯式定義任何的建構函式,但也不要在介面中加入如下程式碼來禁止生成建構函式:

	Testable() = delete;
	Testable(const Testable&) = delete;

因為C++的呼叫機制要求子類的建構函式呼叫時一定會先呼叫父類的建構函式,如果禁止生成建構函式,程式碼編譯時會報錯。如果程式設計師不顯式的提供建構函式,編譯器也會隱式的加上建構函式的,雖然這些建構函式對於介面類來說實際沒有什麼意義。

C++中如何定義標識介面(marker interface)類?

標識介面是沒有任何方法和屬性的介面。這種介面在java中出現的較多,比如:java.io.Serializable、java.rmi.Remote、java.util.EventListener、java.util.RandomAccess

實現程式碼如下:

class Testable {
public:
    virtual ~Testable() = 0 {}; // #5
};

#5.

只要對純虛解構函式提供一個預設實現就可以了。這種對純虛擬函式提供實現的寫法看似很奇怪,但C++的確是支援的。

以上是定義C++介面類的一些重要事項,如果有錯誤或遺漏,請指正。

另外,對於如何正確的使用介面類,請參看下一篇文章“C++:如何正確的使用介面類”。