2011-03-05 76 views
1

例如,在創建類庫時,我想爲每個類指定一個內部API和一個公共API,因此我可以隱藏用戶的一些細節。內部API將被庫中的其他類使用,公共API將被庫用戶使用。在C++中,如何爲一個類創建兩個接口?

可能嗎?

+0

我認爲你需要更清晰。你想做什麼?像「圖書館」,「公共」和「界面」這樣的抽象詞在沒有更多上下文的情況下意義不大。 – tenfour 2011-03-05 19:51:52

+0

查找「平普爾」或「不透明指針」,例如http://en.wikipedia.org/wiki/Opaque_pointer – Erik 2011-03-05 19:54:16

+0

@tenfour編輯。我希望它更清楚。 – subb 2011-03-05 20:06:10

回答

1

在C++中,接口可能意味着很多事情。這可能意味着你在派生類實現,如下面的例子純虛函數,

class Interface 
{ 
public: 
    virtual void f() = 0 ; 
}; 

class Implementation : public Interface 
{ 
public: 
    virtual void f() {} 
}; 

-

或者,它可能意味着你的類只是公共職能:

class A 
{ 
public: 
    void f() {} //public function - an interface that the outside world can 
       //use to talk to your class. 
}; 

你可以使用其中任何一種,並可以使用訪問說明符(公共,受保護,私有)來使你的接口公開或內部/私人!

+0

這是我腦子裏想打提交按鈕後。但是,我想知道是否有另一種方式。在ActionScript中,您可以聲明一個名稱空間並將其用作可見性修飾符。因此,不用'public void f()',你可以做'internal void f()','f'函數只能通過'internal'命名空間來看到。 C++中是否有類似的構造? – subb 2011-03-05 19:55:17

+0

@Subb:你可以寫'public:void f()'。也就是說,每個函數之前的標記'public:'就像在ActionScript中函數之前編寫'internal'一樣。 (我不知道ActionScript的方式)。 – Nawaz 2011-03-05 19:58:21

+0

我想你誤會了我。實際上,您可以指定其他內容而不是公開的可見性修飾符。 – subb 2011-03-05 20:04:09

1

種。

一些圖書館爲此使用好友類/函數。每個類聲明其他類作爲friend■如果他們需要訪問多個「公共」接口:

class Car { 
    friend class Mechanic; 
    private: 
     Engine engine; 
}; 

class Mechanic { 
    // something involving Car::engine... 
}; 

這不是很漂亮,但它的工作原理。


,可能爲你工作,另一種方法是平普爾(指針到實現)成語:

class CarImpl; // declaration only 

class Car { 
    private: 
     CarImpl *impl; 
    public: 
     CarImpl *getImpl(); // doesn't strictly belong in the pimpl pattern 
     // methods that simply call the corresponding methods on impl 
}; 

內部接口可通過電話getImpl()進行訪問。您可以將CarImpl聲明放在明確標記爲內部的頭文件中,以便客戶端不會訪問它。例如,您可以將這些標頭放在名爲internal的子目錄中。

明顯的缺點是Car類有一堆你必須實現的微不足道的方法。


第三種方法,我不建議,就是繼承:

class Car { 
    public: 
     virtual void start() = 0; 
     static Car *create(); 
}; 

而且在內部頭:

class CarImpl : public Car { 
    public: 
     virtual void start(); 
}; 

Car類只公開public接口;要訪問內部接口,內部代碼需要向下執行CarImpl。這很醜陋。

+0

這不是pimpl的成語。你從不暴露皮條;如果你這樣做,它就會失去它的全部目的。 – wilhelmtell 2011-03-05 20:04:31

+0

如果你暴露了pimpl但不是它的類型的定義,我猜,它只能擊敗三分之一的目的。它仍然允許有效的編譯;它仍然只允許暴露部分界面;它只是不允許切換到不同的實現。 – Thomas 2011-03-05 20:05:54

0

我不太清楚你問什麼,但如果你已經定義了一個抽象類:

class Loggable { ... }; 

你可以從它繼承private LY,像這樣:

class User : private Loggable { ... }; 

User類現在有Loggable的成員,但它們是私有的。

請參閱C++ FAQ lite

0

有許多方法可以解決這個。一個是運行時多態性:

struct widget { 
    virtual debug_info diagnose() = 0; 
    virtual void draw() = 0; 
}; 

struct window { 
    virtual void draw() = 0; 
}; 

struct view : public window, public widget { 
    void draw(); 
    debug_info diagnose(); // internal 
}; 

或者編譯時多態性:

struct view { 
    void draw(); 
    debug_info diagnose(); // internal 
}; 

template<class W> 
void do_it(W window) 
{ 
    widget.draw(); 
} 

template<class W> 
void diagnose_it(W widget) 
{ 
    debug_info d = widget.diagnose(); 
} 

另一種方法是,以暴露私有成員於特定功能或類:

struct widget { 
    virtual void draw() = 0; 
}; 

struct view : public widget { 
    friend void diagnose_widget(widget w); 
    void draw(); 
private: 
    debug_info diagnose(); 
}; 

// internal 
debug_info diagnose_widget(widget w) 
{ 
    debug_info d = w.diagnose(); 
} 
0

A C++類有3級保護:公共,受保護和私密。公共事物對每個人都是可訪問的,只對後代保護 - 然後爲自己而不是其他後代 - 對於班級和其朋友是私人的。

這樣的友誼是給予比公共訪問類/函數,而不是一個後代更多的唯一方法,它給予完全訪問權限,這並不總是很方便。

的解決方案,我已經成功使用的是寫一個包裝這是主類的朋友,然後提供給自己的朋友額外的訪問(這是唯一一個能夠構建包裝)。我沒有真正推薦它,這很乏味,但如果你有這樣的需求,它可能會有用。

class Main { 
public: 
    ... 
private: // but wrapped 
    void foo(); 
protected: 
    ... 
private: // and not wrapped 
    void bar(); 
}; 

class Wrapper { 
pubic: 
    void foo() { wrapped.foo(); } 
private: 
    Wrapper(Main& m) : wrapped(ma) {} 
    Main& wrapped; 
    friend void qux(Main&); 
}; 

void qux(Main& m) { 
    Wrapper mwrapped(m) 

    mwrapped.foo(); 
    // still can't access bar 
} 
1

你可以使用很多技巧來給予友誼或給定的幾個「擴展」接口,但它很快很麻煩。

到外部接口從內部接口分離的最簡單方法...是有兩個接口,因此兩個類。

如果你看看由GoF的提出了一套設計模式的偷看,你會發現Proxy模式。

您可以通過類不暴露到庫的外部,而是露出了代理,在其中包裝類,並且只公開其接口的子集使用。

class MyClass 
{ 
public: 
    void foo(); 
    void bar(); 

    void printDebugInfo(); 
    void test(); 
}; 

class MyClassProxy 
{ 
public: 
    MyClassProxy(std::unique_ptr<MyClass> ptr): _ptr(ptr) {} 

    void foo() { _ptr->foo(); } 
    void bar() { _ptr->bar(); } 

private: 
    std::unique_ptr<MyClass> _ptr; 
}; 

我個人覺得這個設計很乾淨。沒有向下傾倒,沒有微妙的繼承技巧,沒有友誼名單比我的手臂長。

相關問題