---
title: C語言 物件導向程式設計篇 心得
tags: C 語言筆記
---
## C語言 物件導向程式設計篇 心得
### Data Encapsulation
* 一種將抽象性函式介面的實作細節部份包裝、隱藏起來的方法。同時,它也是一種防止外界呼叫端,去存取物件內部實作細節的手段
* 在 C 裡可以利用 forward declaration 與 function pointer 來實作(4到11行)
```c=
#include <stdio.h>
#include <stdlib.h>
/* forward declaration */
typedef struct object Object;
typedef int (*func_t)(Object *);
struct object {
int a, b;
func_t add, sub;
};
static int add_impl(Object *self) { // method
return self->a + self->b;
}
static int sub_impl(Object *self) { // method
return self->a - self->b;
}
// & : address of
// * : value of // indirect access
int init_object(Object **self) { // call-by-value
if (NULL == (*self = malloc(sizeof(Object)))) return -1;
(*self)->a = 0; (*self)->b = 0;
(*self)->add = add_impl; (*self)->sub = sub_impl;
return 0;
}
int main(int argc, char *argv[])
{
Object *o = NULL;
init_object(&o);
o->a = 9922; o->b = 5566;
printf("add = %d, sub = %d\n", o->add(o), o->sub(o));
return 0;
}
```
* 因為 Object *o = NULL,傳給 init(o) 後做到 malloc 時會發現只是在 NULL = malloc(...),所以等於沒做,所以才要用 o 的 address 來做
* 所以如果把 malloc 放到 main 做,就可以不用 pointer to pointer
### Inheritance and Polymorphism in C
* [Inheritance-and-Polymorphism-in-C 連結](https://www.codeproject.com/Articles/108830/Inheritance-and-Polymorphism-in-C)
* The Person class representation

* Struture of the Employee object (Inheritance-and-Polymorphism)

### Design Patterns in C
* 情境

* [程式碼](https://github.com/QMonkey/OOC-Design-Pattern/tree/master/Observer)
* [ include/iobserver.h ]: 檔名開頭的 i 字母表示 interface
```c=
typedef struct _IObserved IObserved;
typedef struct _IObserver IObserver;
struct _IObserved { /* 商品 */
void (*registerObserver)(IObserved *, IObserver *);
void (*notifyObservers)(IObserved *);
void (*removeObserver)(IObserved *, IObserver *);
};
struct _IObserver { /* 顧客 */
void (*handle)(IObserver *);
};
```
* 接下來 include 裡的 observed.h 和 observer.h 分別實作介面
* [ include/observed.h ]
```c=
typedef struct _Observed Observed;
struct _Observed {
IObserver **observers;
size_t count;
size_t size;
union {
IObserved;
IObserved iobserved;
};
};
extern Observed *Observed_construct(void *);
extern void Observed_destruct(Observed *);
```
* [ include/observer.h ]
```c=
#include "iobserver.h"
typedef struct _Observer Observer;
struct _Observer {
union {
IObserver;
IObserver iobserver;
};
};
extern Observer *Observer_construct(void *);
extern void Observer_destruct(Observer *);
```
**問題: 為何 struct 的 anonymous union 要這樣寫?**
* 之後才是在 src/observed.c 和 src/observer.c 實作函式
* 最後可以看到 main 裡的使用
* new、delete 是放在 base.h 裡的巨集
```c=
const int OBSERVER_SIZE = 10;
int main() {
Observed *observed = new (Observed);
IObserved *iobserved = &observed->iobserved;
Observer *observers[OBSERVER_SIZE];
for (int i = 0; i < OBSERVER_SIZE; ++i) {
observers[i] = new (Observer);
observed->registerObserver(iobserved, &observers[i]->iobserver);
printf("handle: %p\n", &observers[i]->iobserver);
}
printf("\n");
iobserved->notifyObservers(iobserved);
for (int i = 0; i < OBSERVER_SIZE; ++i)
delete(Observer, observers[i]);
delete(Observed, observed);
return 0;
}
```
### Strategy Pattern
* 為了達到相同的目的,物件可以因地制宜,讓行為擁有多種不同的實作方法。例如,一個壓縮檔案物件,可以採用 zip、arj、rar、tar、7z 等不同的演算法來執行壓縮工作。讓物件可以自由切換演算法或行為實作。
* 用 switch case 會讓開發、修改變難
* 可以為演算法定義一個 Strategy 介面,針對每一種演算法,新增一個實作 Strategy 介面的 ConcreteStrategy 物件。在執行期間藉由改變 Strategy 成員變數所指向的 ConcreteStrategy 物件,來切換不同的演算法演算法。
* 以下範例是定義一個叫 itravel_strategy.h 的 Strategy 介面
```c=
typedef struct _ITravelStrategy ITravelStrategy;
struct _ITravelStrategy {
void (*travel)(ITravelStrategy *);
};
```
* 之後可以在 main 中這樣使用,定義了搭飛機跟坐火車兩種旅行方法,person 要用哪種的 itravelStrategy 不需要變換
```c=
#include "base.h"
#include "itravel_strategy.h"
#include "airplane_strategy.h"
#include "train_strategy.h"
#include "person.h"
int main() {
TrainStrategy *trainStrategy = new (TrainStrategy);
ITravelStrategy *itravelStrategy = &trainStrategy->itravelStrategy;
Person* person = new (Person, itravelStrategy);
person->travel(person);
AirplaneStrategy *airplaneStrategy = new (AirplaneStrategy);
itravelStrategy = &airplaneStrategy->itravelStrategy;
person->setTravelStrategy(person, itravelStrategy);
person->travel(person);
delete (Person, person);
delete (AirplaneStrategy, airplaneStrategy);
delete (TrainStrategy, trainStrategy);
return 0;
}
```