封裝
數據封裝 是面向對象編程的一個重要特點,用於防止函數直接訪問類對象的內部成員。類成員的訪問限制是通過類內關鍵字 public、private、protected 指定標記區域,稱爲 訪問修飾符。
- 一個類可以有多個 public、protected 或 private 標記區域。
- 每個標記區域在下一個標記區域開始之前或者在遇到類主體結束右括號之前都是有效的。
- 類中未指定成員的
默認訪問修飾符是 private
,而結構體中默認爲 public
class ClassName
{
public:
// 公有成員
// 在類內、類外、派生類中都可被訪問
protected:
// 受保護成員:爲了與派生類共享,但又不想公開
// 在類內、派生類中可被訪問,類外不允許
private:
// 私有成員,默認修飾
// 只允許類內訪問,以及友元訪問
};
繼承
面向對象程序設計中最重要的一個概念是繼承,允許依據一個基類來定義一個派生類,以此實現重用代碼功能並提高執行時間。繼承表示了 is a
關係,如狗是哺乳動物,因此狗具有哺乳動物的共性。一個類也可以繼承/派生自多個類。繼承方式同樣有 public、protected、private。
class A :
public Base
{
};
class A :
protected Base
{
};
class A :
private Base
{
};
class A:
public Base_1, protected Base_2, private Base_3
{
};
一個派生類繼承了所有的基類方法,但下列情況 除外:
- 基類的構造函數、析構函數和拷貝構造函數。
- 基類的重載運算符。
- 基類的友元函數
訪問權限
- 所有成員在 類內 都可以被訪問;
- 派生類無法繼承private成員(不可見),其他繼承得到的成員在派生類的 內部 都可被訪問,在派生類外部取決於繼承方式和基類的成員屬性;
- public 成員在類內、類外、派生類中都可被訪問;
- protected 成員是爲了與派生類共享,但又不想公開。因此在類內、派生類中可被訪問,類外不允許;
- private 成員,是默認修飾,只允許類內訪問,以及友元訪問,在派生類中不可見(類內類外都不可訪問)
友元
C++嚴格控制了類中成員的訪問權限,在類外只允許訪問public成員。但有些情況下,需要允許特定的非成員函數訪問一個類的私有成員,同時仍阻止一般的訪問,例如被重載的輸入或輸出操作符,經常需要訪問類的私有數據成員。這就需要爲該類構造“友元”。
一個類在定義時,聲明 某函數 / 某類 / 某成員函數 是其友元 friend,給予對方所有的訪問權限,包括私有(private)成員和保護(protected)成員。因此其友元函數/友元類能訪問該類的所有類型的成員。
class X // 友元成員函數所屬的類必須提前定義
{
public:
X(char);
~X();
char* foo(int);
};
class Base
{
int data; // 私有成員
// 非成員函數的運算符 operator<< 將擁有對 Y 的私有成員的訪問權
friend std::ostream& operator<<(std::ostream& out, const Y& o);
friend char* X::foo(int); // 其他類的成員亦可爲友元
friend X::X(char), X::~X(); // 其他類的構造函數與析構函數也可爲友元
friend class Y; // 友元類聲明
};
// 此 operator<< 仍需定義,作爲非成員
std::ostream& operator<<(std::ostream& out, const Base& base)
{
return out << base.data; // 可訪問私有成員 Y::data
}
- 友元聲明,也是聲明,可以替代預先的函數聲明、類聲明等,但聲明友元成員函數時必須已經定義了其歸屬類。
- 友元關係不能被繼承;
- 友元關係是單向的,不具有交換性。若類 B 是類 A 的友元,類 A 不一定是類 B 的友元,要看在類中是否有相應的聲明;
- 友元關係不具有傳遞性。若類 B 是類 A 的友元,類 C 是 B 的友元,類 C 不一定是類 A 的友元,同樣要看類中是否有相應的申明;
- 友元函數並不是類的成員函數,因此在類外定義友元函數時不能加上
class::ClassName
;