抽象資料類型
設計一個好程式庫的要求之一就是徹底隔離介面和實現,C++的做法是通過構造、解構函式和成員函數:
- C++語言中將介面和實現分隔開的基本的方法之一就是採用建構函式和解構函式。建構函式本身提供了產生給定類對象的方法;解構函式則提供了與建構函式想法的行為。
- 成員函數能夠防止使用者訪問那些他們不應該看到的類成員。
型別安全地連結
使用C庫時,可能一個函數存在於多個庫內,例如sqrt(double)可能在math.h標頭檔內,
extern double sqrt(double);
sqrt(Complex)在複數庫檔案Complex.h內,
extern Complex sqrt(Complex);
此時,可以用這種聲明文法解決:
extern "C" double sqrt(double);
extern "C" Complex sqrt(Complex);
extern "C"這種處理的確切含義取決於特定系統處理C函數的具體方式。
命名空間
命名空間解決了一種在C中十分突出而在C++愈加嚴重的問題:如何防止在不同的程式庫設計者為各自組件採用同樣的名字。
本質上命名空間允許庫設計者對會被庫方到全域範圍的所有名稱指定一個封裝器,它的兩種使用方法:
例如ShadowSoft公司的庫命名空間名為ShadowSoft,其中定義的String s,一種用法是通過使用命名空間標識的名字:
Shadow::String s;
一種是引用命名空間:
using namespace ShadowSoft;
String s;
記憶體配置
這部分講了一個看似衝突的記憶體配置案例:
class Foo{
public:
void*operatornew (size_t);
void*operator delete(void*);
};
這個類自己定義了一套記憶體管理的方案(new、delete),現在,無論何時想在記憶體中建立或釋放一個Foo對象,都得通過Foo::operator new和Foo::operator delete來動態分配記憶體。如果我們通過系統記憶體配置函數申請記憶體,再在此記憶體中建立Foo對象會怎樣呢?例如這樣:
void* p = malloc(1024);
Foo* tp =new (p) Foo;
答案是容器時具有優先權的,new(p) Foo將由p定址的記憶體中分配一個Foo對象,即使類Foo有自己的記憶體 Clerk。
按成員賦值和初始化
對於結構體的賦值,如果結構體成員裡有複雜類型的成員,例如是一個類,我們不清楚該類的賦值過程是按位複製或是其他方法,我們可以顯示的構造和複製。
struct Person
{
string name;
string address;
string telno;
Person();
Person (const Person& p):name(p.name),address(p.address),telno(p.telno) {}
Person operator=(const Person& p)
{
name = p.name;
address = p.address;
telno = p.telno;
return*this;
}
};
注意:沒有必要給Person類一個顯示的解構函式,因為編譯器會正確的從string類的解構函式中繼承解構函式。