天天看點

Essential C++第4章 基于對象的程式設計風格

第4章 基于對象的程式設計風格

這一章,我們會設計并屬于實作我們自己的class。

在之前的幾章,我們已經指定Class的一些相關事項。

1、使用Class之前,要包含相應的頭檔案

2、class名稱被視為一個類型,就像int,double一樣。

3、class會提供一組操作函數,讓我們作用于其object上。

4、class由兩部分組成:一組公開的操作函數;一組私有的實作細節。

4.1 如何實作一個Class

我們從實作一個 棧(stack)開始,實作一個class。

什麼是棧呢,棧是一種存放資料的結構,它允許我們在裡面存放數值,并以 後進先出的順序取出。我們以pushing 方式存入數值,以popping方式取出數值。

使用者可能還需要其他操作,如查詢stack空間是否已滿(full),是否為空(empty),查詢stack元素個數(size)。

Class的聲明以關鍵字 class開始,随後接一個class名稱:

class stack;

class的定義類似這樣:

class Stack {

public:

 //…public接口

private:

//…private實作部分

};

  class 定義有兩部分:class聲明,主體。

  主體中的public和private是通路權限,public 可被程式任何地方通路,private隻能被class内部或class friend 通路。

  stack class的定義如下:

class Stack{

public:

bool push(const string&);

bool pop(string &elem);

bool peek(string &elem);

bool empty();

bool full();

int size() { return _stack.size();}

private:

vector<string> _stack;

};

所有的member function都要在Class内聲明,如果在Class内定義,則會自動被視為inline函數。在Class外定義,必須用特殊的文法:

inline bool

Stack::empty()

{

return _stack.empty();

}

bool

Stack::pop(string &elem)

{

if(empty())

  return false;

elem = _stack.back();

_stack.pop_back();

return true;

}

Inline函數和Class定義 都放在對應的,h檔案中。

非inline函數應該放在和class同名的.cpp檔案中。

下面是Stack member function 的定義。

inline bool Stack::full()

{return _stack.size() == _stack.max_size();}

bool Stack::peek(string &elem)

{

if(empty())

  return false;

elem = _stack.back();

return true;

}

bool Stack::push(const string &elem)

{

if(full())

  return false;

_stack.push_back(elem);

return true;

}

4.2 構造函數和析構函數

編譯器會在每次class object被定義時,調用構造函數(constructor)來進行初始化。

constructor(構造函數)的名稱必須和Class名稱相同。constructor沒有傳回值類型,可以被重載。

最簡單的constructor是default constructor,它不需要接受參數。

參數表為空 或者為每個參數提供預設值。

Member initialization List(成員初始化清單)

Triangular::Triangular(const Triangular &rhs)

:_length(rhs._length),_beg_pos(rhs._beg_pos),_next(rhs._beg_pos-1)

{}

Member initialization list 緊接在參數清單的最後的冒号後面,是個以逗号分隔的清單。

destructor(析構函數)

析構函數是class名稱加上~字首,沒有傳回值,也沒有參數。用來釋放對象的資源(釋放記憶體。析構函數由系統自動調用。

Memberwise initialization(成員逐一初始化)

即當使用一個對象給另一個對象初始化時,對象中的成員會逐一複制。

有時預設的複制操作不符合我們的要求,我們要自定義copy constructor。

類似于:

Matrix:Matrix(const Martrix &rhs){

}

4,3 mutable(可變)可const(不變)

class 設計者在Member function身上标注const,告訴編譯器,這個Member function 不會更改Class Object中的内容。

const修飾符寫于函數參數清單之後,凡是在Class主體以外定義者,如果他是一個const member function ,它必須在聲明和定義處都指定const。

Member function 可以根據const與否而重載,是以可以設計這樣的重載函數:

const BigClass& val() cosnt(return _val);

BigClass& val(){return _val};

針對const的mutable, 将某個成員标示為mutable,就可以宣稱,對這個成員的修改不會破壞class object的常量性。(在const member function中可以修改這個成員)

4.4 this指針

this指針時Member function内用來指向其調用者的指針。

4.5 靜态類成員

static(靜态)data member用來表示唯一的,可以共享的Member。它可以在同一類的所有對象中被通路。

對Class而言,static data member隻有唯一的一份實體。是以我們必須在代碼檔案中提供清楚的定義。

//.cpp

vector<int> Triangular::elems;

如果在class member function内部通路static data member,其通路方式和通路一般資料成員相同。

const static int data member可以在聲明時指定初值。

Static Member function(靜态成員函數)

static可以不用任何具體的對象調用:

如 Triangular::is_elem(7);

并且為了不和具體的對象有關,static Member function 不能通路non-static member。

static Member function的聲明方式是在原函數前加關鍵字static。

在Class主體外進行定義時,無需再加static(此規則也适用于static data member)。

4.6 打造一個Iterator Class

我們可以像定義Member function那樣定義運算符,運算符函數和普通函數很像,差別是它的名稱就是operator加運算符号。

bool  operator==(const Triangular_iterator &) const;

int operatir*()const;

運算符重載的規則:

1、不能引入新的運算符

2、運算符操作數個數不可變

3、運算符優先級不變

4、運算符函數的參數清單至少有一個是class類型的。

運算符定義的方式可以向Member function一樣,

也可以像non member function一樣

Non member function 運算符的參數清單中,一定會比Member運算符多一個參數,也就是this指針。對于Member運算符來說,這個this指針隐式代表左操作數。

前++ 和後++

前++的參數表是空的,

後++的參數表得有一個int參數 inline Triangula_iterator Tirangular_iterator::

operator++(int)

{..

return …;

}

但使用時不需要傳入這個int參數,編譯器自動設定為0。

直接使用

it++;

即可。

4.7 friend 友類

class可以将其他function或class指定為friend,這樣就可以讓他們具備和class member function相同的通路權限,可以通路class 的private member。

隻要在某個函數的原型前加上關鍵字friend就可以将它聲明為某個class的關鍵字。

如果讓class A 認為class B是自己的friend,則class B的所有函數都是A的friend。

4.8實作複制運算符(copy assignment operator)

隻要為Class提供copy assignmemnt operator,它就會被用來取代預設的memberwise copy。

4.9 實作一個function object

function object 是一種提供有function call運算符的class。

通常我們将function object 作為參數傳遞給泛型算法。

function call運算符:

例:

inline bool LessThan::operator()(int value) const {return value<_val;}

4.10 重載iostream運算符

為了讓我們的class支援

cout<<train<<endl;這種形式,我們需要重載iostream運算符。

ostream & operator<<(ostream &os, const Triangular &rhs)

{

 os<<”(“<<rhs._beg_pos()<<”,”<<rhs.length()<<”,”;

rhs.display(rhs.length(),rhs._beg_pos(),os);

return os;

}

類似的可以重載>>運算符。

4.11 指針,指向Class Member Function

指向成員函數的指針和指向普通函數的指針很像,都需要指定傳回類型和參數清單。

不過指向成員函數的指針還要指定 所屬的class

如:

void (num_sequence::*pm)(int) = 0;