C++ Primer Plus 筆記第十章
對象和類
OOP特性:
1. 抽象
2. 封裝和數據隱藏
3. 多態
4. 繼承
5. 代碼的可重用性
10.1 過程性編程和面向對象編程
采用OOP方法時:
1. 描述對象所需的數據以描述用戶與數據交互所需的操作;
2. 確定如何實現接口和數據存儲
10.2 抽象和類
抽象:
將問題本質特征抽象出來,並根據特征來描述解決方案;
抽象是通往用戶定義類型的捷徑,C++中用戶定義類型是實現抽象接口的類設計
類型:
1. 決定數據對象需要的內存數量
2. 決定如何解釋內存中的位(long 和 float 在內存中占用的位數相同,但將他們轉換為數值的方法不同)
3. 決定可使用數據對象執行的操作和方法
10.2.2 C++中的類
類規範由兩部分組成:
類聲明: 以數據成員的方式描述數據部分,以成員函數(方法)的方式描述公有接口
類方法定義: 描述如何實現類成員函數
簡單地說,類聲明提供了類的藍圖,而方法定義提供了細節
什麽是接口:
接口是一個共享框架,供兩個系統交互時使用;
接口讓程序員能編寫與類對象交互的代碼,從而讓程序能夠使用類對象
類聲明:
1 #include<iostream> 2 #include<cstring> 3 4 class Stock5 { 6 private: 7 char company[30]; 8 int shares; 9 double share_val; 10 double total_val; 11 void set_tot() { total_val = shares * share_val; } 12 public: 13 void acquire(const char*co, int n, double pr); 14 void buy(int num, double price); 15 void sell(int num, doubleprice); 16 void update(double price); 17 void show(); 18 };
關鍵字 class 指出這些代碼定義了一個類設計;
Stock 成為一個新的類型名,能夠聲明 Stock 類型的變量,稱為對象或實例:
Stock sally; // 創建 Stock 對象 sally
Stock solly; // 創建 Stock 對象 solly
關鍵字 private 和 public 描述了對類成員訪問控制:
使用類對象的程序都可以直接訪問共有部分;
只能通過共有成員函數訪問對象的私有成員;
共有成員函數提供了對象和程序之間的接口;
防止程序直接訪問數據被稱為數據隱藏:
數據隱藏(將數據放在類的私有部分中)是一種封裝;
封裝的另一個例子,將類函數定義和類聲明放在不同的文件中
數據項通常放在私有部分,組成類接口的成員函數放在共有部分;
不必在類聲明中使用關鍵字 private,因為這是類對象的默認訪問控制
10.2.3 實現類成員函數
類成員函數定義特征:
1. 定義成員函數時,使用作用域解析操作符(::)來標識函數所屬的類
2. 類方法可以訪問類的 private 組件
將類聲明放在頭文件中,而將類成員函數定義放在單獨的一個源代碼文件中;
定義位於類聲明中的函數都將自動成為內聯函數;
調用成員函數時,他將使用被調用他的對象的數據成員:
所創建的每個新對象都有自己的存儲空間,用於存儲其內部變量和類成員;
同一個類的所有對象共享同一組類方法,即每種方法只有一個副本
10.2.4 使用類
C++ 的目標是使得使用類與使用基本的內置類型盡可能相同:
要創建類對象,可以聲明類變量,也可以使用 new 為類對象分配存儲空間;
可以把對象作為函數的參數和返回值,也可以將一個對象賦給另一個對象
使用新類型,最關鍵的是要了解成員函數的功能,而不必考慮實現的細節
10.2.5 小結
類設計:
1. 提供類聲明
class className
{
private:
data member declarations // 將數據放私有部分中可以保護數據的完整性,數據隱藏
public:
member function prototypes
};
2. 實現類成員函數
3. 類成員函數(方法)通過類對象調用
Bozo bozetta;
cout << Bozetta.Retort();
實現文件:
stock1.h 文件提供類聲明:
1 #ifndef STOCK1_H_ 2 #define STOCK1_H_ 3 class Stock 4 { 5 private: 6 char company[30]; 7 int shares; 8 double share_val; 9 double total_val; 10 void set_tot() { total_val = shares * share_val; } 11 public: 12 Stock(); 13 Stock(const char *co, int n = 0, double pr = 0.0); 14 ~Stock(); 15 16 void buy(int num, double price); 17 void sell(int num, double price); 18 void update(double price); 19 void show(); 20 }; 21 22 #endif
stock1.cpp 文件實現了類成員函數的定義
1 #include<iostream> 2 #include "stock1.h" 3 4 Stock::Stock() 5 { 6 std::cout << "Default constructor called\n"; 7 std::strcpy(company, "no name"); 8 shares = 0; 9 share_val = 0.0; 10 total_val = 0.0; 11 } 12 13 Stock::Stock(const char *co, int n, double pr) 14 { 15 std::cout << "Constructor using " << co << " called\n"; 16 std::strncpy(company, co, 29); 17 company[29] = ‘\0‘; 18 19 if (n < 0) 20 { 21 std::cerr << "Number of shares can`t be negative; " 22 << company << " shares set to 0.\n"; 23 shares = 0; 24 } 25 else 26 shares = n; 27 share_val = pr; 28 set_tot(); 29 } 30 31 Stock::~Stock() 32 { 33 std::cout << "Bye, " << company << "!\n"; 34 } 35 36 void Stock::buy(int num, double price) 37 { 38 if (num < 0) 39 { 40 std::cerr << "Number of shares purchased can`t be negative. " 41 << "Transaction is aborted.\n"; 42 } 43 else 44 { 45 shares += num; 46 share_val = price; 47 set_tot(); 48 } 49 } 50 51 void Stock::sell(int num, double price) 52 { 53 using std::cerr; 54 if (num < 0) 55 { 56 std::cerr << "Number of shares purchased can`t be negative. " 57 << "Transaction is aborted.\n"; 58 } 59 else if (num > shares) 60 { 61 cerr << "You can`t sell more than you have! " 62 << "Transaction is aborted.\n"; 63 } 64 else 65 { 66 shares -= num; 67 share_val = price; 68 set_tot(); 69 } 70 } 71 72 void Stock::update(double price) 73 { 74 share_val = price; 75 set_tot(); 76 } 77 78 void Stock::show() 79 { 80 std::cout << "company: " << company 81 << " shares: " << shares << std::endl 82 << " share price: $" << share_val 83 << " Total Worth: $" << total_val << std::endl; 84 }
usestock1.cpp 文件測試
1 #include<iostream> 2 #include "stock1.h" 3 4 int main() 5 { 6 using std::cout; 7 using std::ios_base; 8 cout.precision(2); 9 cout.setf(ios_base::fixed, ios_base::floatfield); 10 cout.setf(ios_base::showpoint); 11 12 cout << "Using constructors to ctreat new objects\n"; 13 Stock stock1("NanoSmart", 12, 20.0); 14 stock1.show(); 15 16 Stock stock2 = Stock("Boffo Objects", 2, 2.0); 17 stock2.show(); 18 19 Stock stock3; 20 stock3.show(); 21 22 return 0; 23 }
10.3.6 構造函數和析構函數小結
構造函數在創建類時被調用;
構造函數的名稱和類名稱相同,通過函數重載可以創建多個同名的構造函數;
構造函數沒有聲明類型;
構造函數用於初始化類對象的成員:
原型: Bozo ( const char * fname, const char * lname );
初始化: Boza bozetta = Bozo ( "Bozetta", "Biggens" );
Bozo fufu ( "Fufu", "O`Dweeb" );
Bozo *pc = new Bozo ("Popo", "Le Peu");
記住: 接受一個參數的構造函數允許使用賦值句法來將對象初始化為一個值
Classname object = value;
默認構造函數沒有參數,如果創建對象沒有顯示地初始化,則將調用默認構造函數;
如果程序中沒有任何構造函數,則編譯器會為程序定義一個默認構造函數;
對象被創建時調用構造函數,被刪除時,程序調用析構函數:
每個類只能有一個構造函數;
析構函數沒有聲明類型,也沒有參數,其名稱為類名稱前加上 ~;
~Bozo ();
如果構造函數使用了 new,則必須提供使用 delete 的析構函數
10.4 this 指針
有時候方法設計兩個對象,在這種情況下需要使用C++的this指針;
const Stock & topval ( const Stock & s) const;
top = stock1.toval (stock2):
函數隱式訪問 stock1,顯示訪問 stock2;
原型括號中的 const 表示,函數不會修改被顯示地訪問的對象;
原型括號後的 const 表示,函數不會修改被隱式地訪問的對象
const Stock & Stock :: topval (const Stock & s) const
{
if (s.total_val > total_val)
return s;
else
return *this;
}
10.5 對象數組
創建同一個類的多個對象,可以創建對象數組;
聲明對象數組的方法與聲明標準類型數組相同:
Stock mystuff [4];
初始化對象數組的方案是,首先使用默認構造函數創建數組元素,然後使用括號中的構造函數創建臨時對象,然後將臨時對象的內容復制到相應的元素中;
警告: 要創建類對象數組,則這個類必須有默認構造函數
10.6 接口和實現小結
修改類的私有部分和實現文件屬於實現變更,實現變更改變了類的內部工作原理;
修改類的公有部分屬於接口變更,接口變更改變了使用類的人可用的編碼方式;
10.7 類的作用域
在類中定義的名稱(類數據成員或類函數成員)作用域為整個類;
類作用域意味著不能從外部直接訪問類的成員,要調用類的公有成員必須通過對象:
Stock sleeper ("Exclusive Ore", 100, 0.25); // 創建對象
sleeper.show() // 使用對象調用成員函數
在定義成員函數時,必須使用作用域解析操作符:
void Stock :: update(double price)
{
. . .
}
在類聲明或成員函數定義中,可以使用未修飾的成員名稱(未限定名稱);
其他情況下,使用類成員名時:
直接成員操作符(.); // 對象
間接成員操作符(->); // 指針
作用域解析操作符(::); // 定義成員函數
作用域為整個類的常量:
1. 在類中聲明一個枚舉
在類中聲明的枚舉的作用域為整個類;
可以用枚舉為整型常量提供作用域為整個類的符號名稱:
class Stock
{
private:
enum {Len = 30};
char company [Len];
. . .
}
這種方式聲明枚舉並不會創建類成員,對象中不包含枚舉;
Len 只是一個符號名稱,編譯器將用 30 替換
2. C++ 引入另一種在類中定義常量的方式——使用關鍵字 static:
class Stock
{
private:
static const int Len = 30;
char company [Len];
. . .
}
這裏創建一個名為 Len 的常量,該常量與其他靜態變量存儲在一起,而不存在對象中;
只有一個 Len 常量,被所有 Stock 對象所共享
10.8 抽象數據類型
ADT以通用的方式描述數據類型,而沒有引入語言或實現細節
10.9 總結
類是用戶定義的類型,對象是類的實例;
C++ 試圖讓用戶定義的類型盡可能與標註類型類似,因此可以聲明對象、指向對象的指針和對象數組;
C++ Primer Plus 筆記第十章