---
# System prepended metadata

title: C語言 物件導向程式設計篇 心得
tags: [C 語言筆記]

---

---
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
![](https://i.imgur.com/05o1QEC.png)
* Struture of the Employee object (Inheritance-and-Polymorphism)
![](https://i.imgur.com/wVXPNEd.png)

### Design Patterns in C
* 情境
![](https://i.imgur.com/QDMpU3w.png)
* [程式碼](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;
}
```


