由於@Steve在評論中已經說過,嵌套類型和這種類型的實例具有相同的名稱這一事實並不是該技術的核心部分。爲了增加封裝,我們甚至可以使用成員函數來訪問實例(儘管它看起來不像名稱空間限定)。例如,你給的例子可以改寫如下沒有任何缺點(當然,也許有,但我無法找到任何此刻):
struct A
{
struct Controls
{
//typedefs/data/functions
};
const Controls & getControls() { return controls_; }
private:
Controls controls_;
};
A a;
A::Controls::iterator = a.getControls().begin();
這裏是我看到memberspaces。成員空間的目標是劃分一個類的命名空間,以便將相關的typedef和方法組合在一起。上面的Controls
類可以在A
之外定義,但它與A
緊密連接(每個A
與Controls
關聯,反之亦然,Controls
只不過是包含它的對象A
的視圖)認爲使其成爲A
的成員感覺「自然」,並且可能還使其與A
(如果需要訪問A
的內部結構)成爲朋友。
所以基本上,成員空間讓我們在單個對象上定義一個或多個視圖,而不會污染封閉的類名稱空間。正如文章中指出的那樣,當你想提供幾種迭代類的對象的方法時,這可能非常有趣。
例如,我們假設我正在編寫一個代表C++類的類;我們稱之爲Class。一個類有一個名字,和它所有基類的列表。爲了方便起見,我想讓一個Class也存儲所有從它繼承的類(它的派生類)的列表。所以我有一個這樣的代碼:
class Class
{
string name_;
list< shared_ptr<Class> > baseClasses_;
list< shared_ptr<Class> > derivedClasses_;
};
現在,我需要一些成員函數添加/刪除基類/派生類:
class Class
{
public:
void addBaseClass(shared_ptr<Class> base);
void removeBaseClass(shared_ptr<Class> base);
void addDerivedClass(shared_ptr<Class> derived);
void removeDerivedClass(shared_ptr<Class> derived);
private:
//... same as before
};
有時,我可能需要添加一個方法在基類和派生類迭代:
class Class
{
public:
typedef list< shared_ptr<Class> >::const_iterator const_iterator;
const_iterator baseClassesBegin() const;
const_iterator baseClassesEnd() const;
const_iterator derivedClassesBegin() const;
const_iterator derivedClassesEnd() const;
//...same as before
};
我們面對的仍然是可控的名字的數量,但是,如果我們要添加反向迭代是什麼?如果我們更改存儲派生類的基礎類型,該怎麼辦?這將增加另一堆typedefs。此外,您可能已經注意到,我們提供對開始和結束迭代器的訪問方式不符合標準命名,這意味着我們無法使用通用算法(如Boost.Range),而無需額外的工作。
事實上,在查看成員函數名稱時我們很明顯地看到,我們使用前綴/後綴對它們進行邏輯分組,這是我們現在嘗試避免的,因爲我們有名稱空間。但是因爲我們不能在類中使用名稱空間,所以我們需要使用一個技巧。
現在,使用成員空間,我們將所有基本相關和派生相關的信息封裝在它們自己的類中,這不僅讓我們將相關數據/操作組合在一起,還可以減少代碼重複:由於操作基類和派生類是一樣的,我們甚至可以使用一個單一的嵌套類:
現在我可以這樣做:
Class c;
Class::DerivedClasses::const_iterator = c.derivedClasses.begin();
boost::algorithm::find(c.derivedClasses, & c);
...
在此示例中,嵌套類不那麼耦合到Class
,所以可以定義爲o utside,但你可以找到一個更強大的範例。
好吧,在這篇長文後,我注意到我沒有真正回答你的問題:)。所以不,我從未在我的代碼中實際使用過成員空間,但我認爲它有它的應用程序。
我已經考慮了一次或兩次,特別是當我爲一個圖書館編寫一個外觀類時:外觀旨在通過擁有一個入口點使圖書館更易於使用,但是因此它有幾個成員功能都是相關的,但具有不同程度的「相關性」。而且,它表示一組對象,所以它除了包含「面向特徵」的成員函數之外,還包含與迭代有關的typedef和成員函數。我考慮使用成員空間將邏輯「子空間」劃分爲一個更清晰的接口。不知道爲什麼我沒有做到這一點。
Eeewww!令人討厭!布萊什! – 2011-03-11 00:29:07