為了解決全域變數的問題,創建一個儲存用的函數 connect_address_pool
:
void connect_address_pool(void ****get_address_pool, void **get_index){
/*用於儲存記憶體地址池的空間*/
static void **address_pool = NULL;
static int index = 0; //address_pool 的索引
*get_address_pool = &address_pool;
*get_index = &index;
}
只要利用:
/*用於取得記憶體地址池的資料*/
void ***address_pool = NULL;
int *index;
/*取得記憶體地址池的資料*/
connect_address_pool(&address_pool, &index);
就可以中任意地方操作 connect_address_pool
函數中儲存的變數的值。
這樣的操作包含了輸入、輸出兩個部分,
根據 最小權限原則 以及物件導向的封裝性,connect_address_pool
是連結的方式,給出的權限太多,不符合。
我們需要獲得更好的封裝性,
應該製作 getter 和 setter 這樣的轉接口。
標記的部分 register_address
功能跟 setter 差不多,
所以以下實作 getter 。
void get_address_pool(void ***get_address_pool, int *get_index){
/*用於取得記憶體地址池的資料*/
void ***address_pool = NULL;
int *index;
/*取得記憶體地址池的資料*/
connect_address_pool(&address_pool, &index);
*get_address_pool = *address_pool;
*get_index = *index;
}
注意第二項參數是 int*
而不能是 void*
,因為是 void
是不完全類型。
有關知識點可參看 Days 7: 重溫指標:數據、數據類型的本質。
只不過是 connect_address_pool
的弱化版...
變成單純的按址傳值,沒有了反向修改函數內的值的能力。
由連接變成閱讀。
下面修改釋放的部分 free_all_register_address
。
free_all_register_address
原本的樣子是怎樣?void free_all_register_address(void) {
/*用於取得記憶體地址池的資料*/
void ***address_pool = NULL;
int *index;
/*取得記憶體地址池的資料*/
connect_address_pool(&address_pool, &index);
/*遍歷 address_pool 的空間*/
for (int i = 0; i < *index; i++) {
free((*address_pool)[i]); //釋放曾經記錄過的記憶體地址的空間
(*address_pool)[i] = NULL;
}
/*釋放用於紀錄的空間*/
free(*address_pool);
*address_pool = NULL;
}
使用連結的方式,要宣告 ***address_pool
, *index
,
使用時又要用 *address_pool
, *index
,
這種不方便、不好看的形式。
void free_all_register_address(void) {
/*用於取得記憶體地址池的資料*/
void **address_pool = NULL;
int index;
/*取得記憶體地址池的資料*/
get_address_pool(&address_pool, &index);
/*遍歷 address_pool 的空間*/
for (int i = 0; i < index; i++) {
free(address_pool[i]); //釋放曾經記錄過的記憶體地址的空間
address_pool[i] = NULL;
}
/*釋放用於紀錄的空間*/
free(address_pool);
address_pool = NULL;
}
樣子幾乎沒有分別,
不過 free_all_register_address
可操作的權限減少了,
只能讀取數據,不能反向修改儲存數據的值。
不需要宣告 ***address_pool
, *index
這些高維度的變數,
》高維度 = 抽象 = 難以理解 = 難以維護。
也不需要用 *address_pool
, *index
,
這種不方便、不好看的形式。
getter 和 setter 出現了,
不過使用者還是可以直接調用 connect_address_pool
,
即 變數還是 public
的。
封裝失敗,全卷完。
咳。沒有記錯的話,
巨集是可以覆蓋函數的,所以只要,
#define connect_address_pool() printf("欸欸,不要用這個函數哦。");
注意這個巨集宣告必須放置在 被覆蓋函數 以及 任何使用到該函數 的 函數 後。
使用者就無法調用 connect_address_pool
,
這樣就可以把變數由 public
-> private
了喔。
有沒有發現跟 隊列 這種資料結構很相似,
要更進一步的話,可以用結構體(struct)封裝出一個隊列,
然後用 push(), pop() 這樣的函數進行操作。
代碼量可能會更少或更漂亮。
不過這一部分我就不做出來了。
最小權限原則 - 維基百科,自由的百科全書
https://zh.wikipedia.org/zh-hk/%E6%9C%80%E5%B0%8F%E6%9D%83%E9%99%90%E5%8E%9F%E5%88%99
封裝 (物件導向程式設計) - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/%E5%B0%81%E8%A3%9D_(%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88)