更多 C++ 習語/智慧指標
外觀
當控制代碼體 習語或信封信 習語正在使用時,減輕在控制代碼類中重複主體類的簽名更改的負擔。
- 整體委託
當使用控制代碼/主體習語時,可能需要在控制代碼類中重複主體類的介面,因為控制代碼由使用者程式碼使用。這種重複通常很乏味且容易出錯。智慧指標習語用於減輕這種負擔。智慧指標習語通常與控制代碼類中的某種“智慧”一起使用,例如引用計數、自動所有權管理等。
根據預期的用途,至少有兩種實現智慧指標習語的重疊方法。
- 完全指標語義
- 不太像指標的語義
以上兩種變體都在所謂的“控制代碼”類中定義了一個過載的箭頭運算子。讓我們從完全指標語義開始。
class Body;
class Handle // Completely pointer like semantics
{
public:
void set (Body *b) { body_ = b; }
Body * operator -> () const throw()
{
return body_;
}
Body & operator * () const throw ()
{
return *body_;
}
private:
mutable Body *body_;
};
int main (void)
{
Handle h;
h.set(new Body());
h->foo(); // A way of invoking Body::foo()
(*h).foo(); // Another way of invoking Body::foo()
}
僅使用 -> 運算子可以減輕在控制代碼類中重複主體類介面的問題。另一種方法是像上面程式碼片段中顯示的那樣過載解引用 (*) 運算子,但它不像前者那樣自然。如果控制代碼抽象是某種指標抽象,那麼應該提供這兩個過載運算子(例如,std::auto_ptr、boost::shared_ptr)。如果控制代碼抽象不是指標類抽象,則不需要提供 * 運算子。相反,為常量控制代碼提供過載的箭頭運算子集可能很有用,因為客戶端始終與控制代碼類物件互動。對於客戶端程式碼,控制代碼**就是**物件,因此控制代碼的常量性應該在適當的時候傳播到相應的主體。通常,應該避免從常量控制代碼中修改非常量主體物件的不明確行為。與純粹的指標語義不同,在某些情況下,從控制代碼類到主體類的自動型別轉換也是可取的。
class Body;
class Handle // Less pointer like semantics
{
public:
void set (Body *b) { body_ = b; }
Body * operator -> () throw()
{
return body_;
}
Body const * operator -> () const throw()
{
return body_;
}
operator const Body & () const // type conversion
{
return *body_;
}
operator Body & () // type conversion
{
return *body_;
}
// No operator *()
private:
mutable Body *body_;
};
int main (void)
{
Handle const h;
h.set(new Body());
h->foo(); // compiles only if Body::foo() is a const function.
}
使用成員轉換函式的另一種方法是使用非成員獲取 習語,如下所示。根據介面原則,過載的非成員 get() 函式必須與控制代碼類位於同一個名稱空間中。
namespace H {
class Body;
class Handle { ... }; // As per above.
Body const & get (Handle const &h)
{
return *h.body_;
}
Body & get (Handle &h)
{
return *h.body_;
}
} // end namespace H.
int main (void)
{
H::Handle const h;
h.set(new Body());
get(h).foo(); // compiles only if Body::foo() is a const function.
}
- std::auto_ptr(完全指標語義)
- boost::shared_ptr(完全指標語義)
- C++ 中的 CORBA Var 型別(TAO(ACE ORB)中的 TAO_Seq_Var_Base_T< T > 類 - 不太像指標的語義)