【C++ Primer Plus】學習筆記--第10章 物件和類

Ref.Ptr發表於2021-01-05


10.1 物件導向程式設計

物件導向程式設計(OOP)特性:

  • 抽象
  • 封裝和資料隱藏
  • 多型
  • 繼承
  • 程式碼的可重用性

10.2 抽象和類

P341

C++中的類

是一種將抽象轉換為使用者定義型別的C++工具,它將資料表示操縱資料的方法組合成一個簡潔的包。

類規範由兩部分組成: 類宣告提供了類的藍圖,而方法定義則提供了細節。

  • 類宣告:以資料成員的方式描述資料部分,以成員函式(被稱為方法)的方式描述公有介面。
  • 類方法定義:描述如何實現類成員函式

注意】:宣告類只是描述物件的形式,並沒有建立類,在建立類之前,將沒有用於儲存值的空間

通常,C++程式設計師將介面(類定義)放在標頭檔案中,並將實現(類方法的程式碼)放在原始檔中。

類設計儘可能將公有介面和實現細節分開,被稱為封裝
資料隱藏(將資料放在類的私有部分)也是一種封裝,將實現細節隱藏在私有部分中,也是一種封裝。將類函式定義和類宣告放在不同的檔案中,也是封裝。

從使用者的角度看,只需要知道是成員函式的功能,並不關心使用的哪種方法。原則是將實現細節從介面設計中分離出來

技巧1】:常見的約定------將類名的首字母大寫
技巧2】:資料項放在私有部分組成類介面的成員函式放在公有項


類和結構的唯一區別

類的預設訪問型別為私有private,而結構是公有public

實現類成員函式

  • 定義成員函式時,使用作用域解析運算子(::)來標識函式所屬的類
  • 類方法可以訪問類的private元件

內聯方法

其定義位於類宣告的函式都將自動成為行內函數

程式碼如下(示例):

class Stock
{
	void set_tot() //方法一:類宣告中定義
	{
		//...
	}
};

等價於

class Stock
{
	void set_tot()};
inline void Stock::set_tot()  //方法二:類外內聯
{
	//...
}

方法使用了那個物件?

所建立的每一個類物件都有自己的儲存空間,用來儲存其內部變數,但同一個類的所有物件共享同一組類方法
在這裡插入圖片描述
在OOP中,呼叫成員函式被稱為傳送訊息

使用類

使用成員運算子句點呼叫類公有方法。

Stack sta; //建立物件
sta.set_tot(); //呼叫類方法

10.3 類的建構函式和解構函式

P352

類建構函式,專門用於構造新物件、將值賦給它們的資料成員。

建構函式宣告和定義

class Stock
{
public:
// constructor prototype with some default arguments
	Stock(const string& company, long shares = 0);
private:
	std::string m_company;
	long m_shares;
}
//construckor definition
Stock::Stock(const string& company, long shares)
{	
	m_company = company;
	m_shares = shares;
}

// 建構函式初始化列表
Stock::Stock(const string& company, long shares)m_company(company), m_shares(shares){}

預設建構函式

在建立物件時,如果類內當且僅當沒有提供任何建構函式,則C++將自動提供預設建構函式

Stock::Stock(){}  //預設建構函式
//沒有提供任意建構函式,下面建立正確
Stock stock1; //yes
//提供了非預設建構函式,下面的建立報錯
Stock stock1; //no

這樣做的原因可能是:想禁止建立未初始化的物件

注意】:通常,應初始化所有的物件,以確保所有成員一開始就有已知的合理值。

Stock first("Tom", 20); //呼叫有參建構函式
Stock second(); // 定義一個返回為Stock物件的函式
Stock third; //呼叫預設建構函式

解構函式

物件結束其生命週期,系統自動執行解構函式。作用:清理善後工作

如果建構函式使用new來分配記憶體,則解構函式將使用delete來釋放記憶體。如果沒有使用new,解構函式沒有要完成的任務。

//解構函式原型
~Stock();
//解構函式定義
Stock::~Stock(){}

類中必須有解構函式。如果程式設計師沒有提供解構函式,編譯器將隱式地宣告一個預設解構函式。並在發現導致物件被刪除的程式碼後,提供預設解構函式的定義。

const成員函式

保證函式不會修改呼叫物件。

void show() const;

void Stock::show() const

技巧】:只要類方法不修改呼叫物件,就應將其宣告為const

10.4 為啥要用到this指標呢?

P363

有時候方法可能涉及到兩個物件時,需要使用C++的this指標

看下面的例子:

//比較兩個物件,問題在於不能返回當前物件
const Stock& topval(const Stock& s) const
{
	if (s.val > val)
	{
		return s;
	}
	return ??? ;
}
//返回型別為引用意味著返回的是呼叫物件本身,而不是其他副本。

為了解決此問題,使用被稱為this的特殊指標,this指標指向用來呼叫成員函式的物件

this指標指向呼叫物件的地址;*this引用呼叫物件。

10.5 物件陣列

P368

使用者通常要建立同一類的多個物件建立物件陣列更為合適。

建立方法

Stock mystuff[4]; //creates an array of 4 Stock objects

Stock stocks[3] = {
Stock("NanoSmart", 12.5, 20),
Stock("Boffo Objects", 200, 2.0)
};

10.6 類作用域

P370

在類中定義的名稱的作用域是整個類。

作用域為類的常量

不可以在類中直接建立const常量

class Stock{
const int Months = 12; // fails
}

因為宣告類只是類的藍圖,在建立物件前,沒有用於儲存值的空間

如何實現作用域為類的常量呢

第一種是類中宣告一個列舉

class Stock{
enum {Months = 12}; // 列舉建立常量
int Stocks[Months]; //將常量用於陣列
}
// 由於使用列舉只是為了建立符號常量,並不打算建立列舉型別的變數,因此不需要提供列舉名。

用這種方式宣告列舉並不會建立類資料成員。所有物件都不包含列舉。Months只是一個符號名稱,在類中遇到Months,編譯器將會用12替換它。

另一種是使用關鍵字static

class Stock{
static const int Months = 12; // static建立常量
int Stocks[Months]; //將常量用於陣列
}

該常量將與其他的靜態變數儲存在一起,不是儲存在物件中

作用域內列舉(C++11)

傳統的列舉有些問題

//無法編譯,位於相同的作用域,發生衝突。
enum egg{small};
enum shirt{small};

C++11提供了一種新列舉,其列舉作用域為類

enum class egg{small};  //可以編譯
enum class shirt{small};

C++98中,包含列舉結構的長度可能隨系統而異。
C++11中,作用域內列舉的底層型別為int

10.7 抽象資料型別

P373

實現stack資料型別。

相關文章