例如,在創建類庫時,我想爲每個類指定一個內部API和一個公共API,因此我可以隱藏用戶的一些細節。內部API將被庫中的其他類使用,公共API將被庫用戶使用。在C++中,如何爲一個類創建兩個接口?
可能嗎?
例如,在創建類庫時,我想爲每個類指定一個內部API和一個公共API,因此我可以隱藏用戶的一些細節。內部API將被庫中的其他類使用,公共API將被庫用戶使用。在C++中,如何爲一個類創建兩個接口?
可能嗎?
在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.
};
你可以使用其中任何一種,並可以使用訪問說明符(公共,受保護,私有)來使你的接口公開或內部/私人!
這是我腦子裏想打提交按鈕後。但是,我想知道是否有另一種方式。在ActionScript中,您可以聲明一個名稱空間並將其用作可見性修飾符。因此,不用'public void f()',你可以做'internal void f()','f'函數只能通過'internal'命名空間來看到。 C++中是否有類似的構造? – subb 2011-03-05 19:55:17
@Subb:你可以寫'public:void f()'。也就是說,每個函數之前的標記'public:'就像在ActionScript中函數之前編寫'internal'一樣。 (我不知道ActionScript的方式)。 – Nawaz 2011-03-05 19:58:21
我想你誤會了我。實際上,您可以指定其他內容而不是公開的可見性修飾符。 – subb 2011-03-05 20:04:09
種。
一些圖書館爲此使用好友類/函數。每個類聲明其他類作爲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
。這很醜陋。
這不是pimpl的成語。你從不暴露皮條;如果你這樣做,它就會失去它的全部目的。 – wilhelmtell 2011-03-05 20:04:31
如果你暴露了pimpl但不是它的類型的定義,我猜,它只能擊敗三分之一的目的。它仍然允許有效的編譯;它仍然只允許暴露部分界面;它只是不允許切換到不同的實現。 – Thomas 2011-03-05 20:05:54
我不太清楚你問什麼,但如果你已經定義了一個抽象類:
class Loggable { ... };
你可以從它繼承private
LY,像這樣:
class User : private Loggable { ... };
User
類現在有Loggable
的成員,但它們是私有的。
請參閱C++ FAQ lite。
有許多方法可以解決這個。一個是運行時多態性:
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();
}
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
}
你可以使用很多技巧來給予友誼或給定的幾個「擴展」接口,但它很快很麻煩。
到外部接口從內部接口分離的最簡單方法...是有兩個接口,因此兩個類。
如果你看看由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;
};
我個人覺得這個設計很乾淨。沒有向下傾倒,沒有微妙的繼承技巧,沒有友誼名單比我的手臂長。
我認爲你需要更清晰。你想做什麼?像「圖書館」,「公共」和「界面」這樣的抽象詞在沒有更多上下文的情況下意義不大。 – tenfour 2011-03-05 19:51:52
查找「平普爾」或「不透明指針」,例如http://en.wikipedia.org/wiki/Opaque_pointer – Erik 2011-03-05 19:54:16
@tenfour編輯。我希望它更清楚。 – subb 2011-03-05 20:06:10