# C++ 物件導向高級程式學習筆記
###### tags: `Software Engineering` `Code` `C++`
> 紀錄:Jimmy Shen
> Reference video link: https://youtu.be/2S-tJaPKFdQ (主要參考資源: 高清 1080P C++面向对象高级编程(侯捷))
## 1. C++程式簡介
* 編寫C++的兩種實作
* 基於對象(**Object Based**)
* C++ class
* class without pointer members: EX: Complex
* class with pointer members: EX: String
* 物件導向(**Object Oriented**)
* Classes之間的關係
* 繼承(inheritance)
* 複合(composition)
* 委託(delegation)
* 歷史簡介
* C++語言(1983發明)
* 正式版: C++ 98 (v1.0) (1998)
* C++ 03 (TR1, Technical Report 1)
* C++ 11 (v2.0) (加入許多STD標準庫)
* C++ 14
* C++歸納
* C++語言
* 基本語法
* C++標準庫
* 相關應用程式庫
## 2. 標頭檔(header.h)與類(Class)的聲明

> C語言內有Data與Function來操作變數,但是會被外界看到的(Global值),可能會有複用的問題
> C++中,有class的概念,操作變數只會被class內部的Data Member以及 Member Function調用,具有保護機制
* C++ 程式碼基本形式
* **.h(header files for own)**
* Classes Declaration (聲明)
* **.cpp**
* ex: main()檔案
* 會引用標頭檔,如:```#include <isostream.h>``` and ```#include "complex.h"```
* 延伸文件名稱(extension file name或稱副檔名)不一定是.h或.cpp,也可能是.hpp 或是 其他 或是 無延伸名,如何分別角括號與引號請見[這裡](https://docs.microsoft.com/zh-tw/cpp/preprocessor/hash-include-directive-c-cpp?view=msvc-170)
* **.h(header files for STD)**
* 標準庫 Standard Library
* 在C++中,通常沒有延伸名,EX:```#include <iostream>```
* C++中,如果要引用C的函式庫的話,可以在原本C的標頭檔前,加上c並去掉.h即可,如:```#include <stdio.h>```變成```#include <cstdio>```
### 標頭檔的防衛式聲明 - Header Guard
:::success
所有標頭檔都應該使用 #define 防止標頭檔被多次引入
:::
在標頭檔中,為了防止**重複編譯**的事情發生,專案中會使用防衛式聲明(又稱頭哨兵),來防護標頭檔被重複引用後,出現重複編譯的問題。寫法如下:
```cpp=
#ifndef COMPLEX_
#define COMPLEX_
// The contexts we write
//
//
#endif
```
這邊參照Google Coding Style的寫法,建議的命名格式為 \<PROJECT\>\_\<PATH\>\_\<FILE\>\_H\_
### Header標頭檔佈局
使用以下範例作為介紹,請**注意註解**的說明:
```cpp=
#ifndef COMPLEX_
#define COMPLEX_
#include <cmath>
class ostream; // 0. 前置聲明: forward declarations
class complex; // Google Coding Style不建議使用前置聲明
complex&
__doapl (complex* ths, const complex& r)
////////////
/// class head
class complex // 1. 類-聲明: class declarations
{
/// class body
public:
complex (double r = 0, double i = 0)
: re (r), im (i)
{ }
complex& operator += (const complex&); // 定義放在body之外做定義
double real () const { return re; } // 有些函數可以在此直接定義
double imag () const { return im; } // 這種定義方式叫做內聯(inline),優點是編譯速度快,但不能過於複雜
// 另外,回傳值前加入const,表示回傳值不可改變
private:
double re, im;
friend complex& __doapl (complex*, const complex&);
};
////////////
complex::function ... // 2. 類-定義: class definition
#endif
```
### class template (模板)簡介
使用模板,可以減少程式量,而達到不同型別之適用。原理為,先命名一個T讓編譯器暫時保留型別,最後再讓使用者可以去定義這個型別。
```cpp=
template<typename T>
class complex
{
public:
complex (T r = 0; T i = 0)
: re (r), im (i)
{ }
complex& operator += (const complex&);
T real () const { return re; }
T imag () const { return im; }
private:
T re, im;
...
}
//////////// When we apply:
complex<double> c1(2.5, 1.5);
complex<int> c2(2, 6);
```
## 3. 建構子函數
相關程式碼範例,請往上滑動到[標頭檔佈局](#Header標頭檔佈局)
### inline-內聯函數
```cpp=
double imag () const { return im; } // This is an inline function.
// equal to:
inline double
imag(const complex& x)
{
return x.imag ();
}
```
> Reference: https://dotblogs.com.tw/v6610688/2013/11/27/introduction_inline_function
### access level-訪問級別
:::success
class 資料內部數據,盡量以private儲存,以達到封裝效果
:::
* ```public:``` 公開級別
* 外部檔案物件可以去訪問、提取這個區間的變數或函式
* 公開的,可以被內、外部看到使用的
* 可以被繼承
* ```private:``` 私用級別
* 外部檔案物件**無法**去訪問、提取這個區間的變數或函式
* 私用的,只能被class內部看見使用,達到封裝的效果
* 不能被繼承
* class內部有正在運作、處理的資料(數據),可以存成此級別
* ```protected:``` 被保護級別
* 外部檔案物件**無法**去訪問、提取這個區間的變數或函式
* 受保護的,只能被class內部看見使用
* **可以被繼承**
### constructor (ctor, 建構子函數)
:::success
對於建構子函數的初始化,請善用**initialization**的寫法
:::
以下為建構子函數範例:
```cpp=
complex (double r = 0, double i = 0) // default argument (默認實參)
: re (r), im (i) // initialization (初始列)
{ }
```
使用初始列來初始化參數,可以加快程式編譯、運行流程,而非使用assignments的方式,如:```re = r; im = i;```
對於使用建構子函數,使用以下方式可以宣告建構子函數:
```cpp=
{
complex c1(2, 1);
complex c2;
complex* p = new complex(4);
...
}
```
### overloading (多載)
> Reference link: https://www.csie.ntu.edu.tw/~r95116/CA200/slide/C3_Overloading.pdf
在class內,可以使用overloading的方式撰寫函式,如以下範例:
```cpp=
// 寫法一
double real () const { return re; }
// 寫法二
void real (double r) { re = r; }
```
以上這兩種寫法,代表不一樣的兩個函式,雖然名稱一樣,但經由不同的定義讓函式實現overloading。原因為,real函數編譯後的實際名稱可能為(取決於編譯器):
```objectivec=
?real@Complex@@OBENXZ
?real@Complex@@QAENABN@Z
```
---
## 4. 參數傳遞與返回值
### Singleton-constructor (ctor, 建構子函數)被放在private區
> Reference: https://shengyu7697.github.io/cpp-singleton-pattern/
> 應用時機:整份程式裡面,只容許**唯一一個class實例**進行時,可以應用。
有的建構子函數是可以放在private區域,他無法被外界呼叫。這種寫法叫做**Singleton**(單例)
範例程式:
```cpp=
class A {
public:
static A& getInstance() {
static A a;
return a;
}
setup() { ... }
private: // 注意,建構子位於private位置
A() {};
A(const A& rhs) {};
...
};
/// 呼叫這個class時,使用以下方式
A::getInstance().setup(); // 使用這個函數取得這個class
```
### const member functions (常量成員函式)
:::success
class內部應該要加const就要加 (如果函式不會改動數據)
:::
class在寫回傳值時,要注意是否使用const的問題。加上const於大括號"{}"前,代表回傳值為常量,不可改變。如以下範例:
```cpp=
double real () const { return re; } //注意在"{"前面的 const
double imag () const { return im; }
```
這樣的程式碼寫法,是因應以下的函式呼叫方式:
```cpp
const complex c1(2, 1); //創建一個const類型的class
cout << c1.real();
cout << c1.imag();
```
使用者已經說明c1不能被改變值(加上const),但若在設計class時,回傳值沒有加上const,代表這數值可能會在real或imag被改變數值。因此與使用者的理念相違。
### 參數傳遞: pass by value vs. pass by reference(to const)
:::success
接收傳遞進來的參數,盡量以reference的方式傳遞(有例外須看狀況)
:::
1. **Pass by value**
* 傳遞"整包"資訊,若傳遞資料量大,會比較慢
* 使用時機:被傳遞的變數,若**沒有被分配記憶體位址**,則使用此傳遞方式
* 範例:
```cpp=
//建構子中,傳遞的double值 r 以及 i
complex (double r = 0, double i = 0) // Here
: re (r), im (i)
{ }
```
2. **Pass by reference**
* 傳遞這項變數的"指針(位址)",4個bytes,傳遞速度快,直接去引用該位置的資料
* 傳遞的這項變數,**有可能被改變**
* 使用時機:被傳遞的變數,值有可能會改變,也有被分配記憶體位置時
* 範例:
```cpp=
ostream&
operator << (ostream& os, const complex& x){ // ostream傳遞位址,os這個變數將會被改變
return os << '(' << real (x) << ','
<< imag (x) << ')';
}
```
3. **Pass by reference to const**
* 同2.的性質,傳遞位址
* 但傳遞的這項變數,**無法被改變**
* 使用時機:被傳遞的變數,被傳遞的值不可能會被改變,又有被分配記憶體位置時
* 範例:
```cpp=
complex& operator += (const complex&);
// += 右邊的變數,是被加的,不會改變其量值,因此加上const
```
### 返回值傳遞: return by value vs. return by reference(to const)
:::success
返回值盡量以reference的方式來傳(有例外須看狀況)
:::
1. **return by value**
* 回傳整包參數資料
* 使用時機:要傳的東西,會消亡(local變數),本來就++沒有其位址++。所以傳引用(reference)的話,會抓到亂碼,此時就不能傳引用
* 範例:
```cpp=
double real () const { return re; } // 回傳值,因其沒有位址
```
2. **return by reference**
* 回傳參數位址,速度快
* 使用時機:平常可以不用return by value的情況,盡量使用;或是最後回傳要進行assign value時可以使用
* 範例:
```cpp=
complex& operator += ( const complex& ); // 回傳的值需要"賦值" 給變數
```
### friend (友元)
凡是加了friend關鍵字,即可自由取得private的成員。
```cpp=
// in class
friend complex& __doapl (complex*, const complex& r);
// in definition
inline complex&
__doapl (complex* ths, const complex& r)
{
ths->re += r.re; //自由取得friend的private成員
ths->im += r.im;
return *ths;
}
```
另外,**相同class的各個objects互為freind**,如以下範例:
```cpp=
class complex
{
public:
complex (double r = 0, double i = 0)
: re (r), im (i)
{ }
////// ***
int func(const complex& param)
{ return param.re + param.im; }
//////
private:
double re, im;
}
////// In testing
{
complex c1(2, 1);
complex c2;
c2.func(c1); // c2是可以呼叫func取用c1 private參數
}
```
### class body 外的各種定義(definitions) => 跳過,直接在下一章節一並講解
---
## 5. 操作符多載與臨時物件
> operator overloading 為全局函數(globel functions)
### operator overloading(操作符重載-1, 成員函數) this
* 當重新撰寫操作符(operator)時,會遇到兩種狀況,此為第一種狀況,僅有兩個變數,其中第一參數會被改動,且需要被賦值;第二參數不動
* 這種操作符,通常會有一個**隱藏的**成員函數-this
* 直接下範例,說明do assignment plus的實作:
```cpp=
// do assignment plus (the STD function)
inline complex& // ** 傳遞者不需要知道接收者是以reference形式接收 **
__doapl (complex* ths, const complex& r)
{
ths->re += r.re; //第一參數(ths)將會被改動 => 因此不加const詞綴,並且return by ref.
ths->im += r.im; //第二參數(r)不會被改動 => 因此使用const& 詞綴
return *ths; // ** 傳遞者不需要知道接收者是以reference形式接收 **
}
// we reference this function
inline complex&
complex::operator += (const complex& r)
{
return __doapl (this, r); // 注意隱藏關鍵字this
}
/////// When we implement:
{
complex c1 (2, 1);
complex c2 (5);
c2 += c1;
// or
c3 += c2 += c1; //為此,我們必須return by ref.
}
```
### operator overloading(操作符重載-2, 非成員函數) (無this) 與 temp object(臨時物件) typename()
> reference: https://data-flair.training/blogs/operators-in-c-and-cpp/
* 為了對付client的三種可能用法,需要開發三個對應的函數
* 此外,下面這些函數**絕不可以**return by reference,因為返回的必定是個local object
* typename() => 創建臨時物件 的方法
```cpp=
inline complex // pass by value,返回local object
operator + (const complex& x, const complex& y)
{
return complex (real (x) + real (y),
imag (x) + imag (y));
// complex() => 這就在創建一個臨時對象,其資料為暫存,function結束後就消失
}
inline complex
operator + (const complex& x, double y)
{
return complex (real (x) + y, imag (x));
}
inline complex
operator + (double x, const complex& y)
{
return complex (x + real (y), imag (y));
}
///
// 此為return by reference的範例,會改變os這項值並做回傳
ostream&
operator << (ostream& os, const complex& x){
return os << '(' << real (x) << ','
<< imag (x) << ')';
}
```
---
## Summary
> reference: https://www.youtube.com/watch?v=IRfN6rg0jmg
:::success
1. 所有標頭檔都應該使用 #define 防止標頭檔被多次引入
2. class 資料內部數據,盡量以private儲存,以達到封裝效果
3. 對於建構子函數的初始化,請善用initialization的寫法
4. class內部應該要加const就要加 (如果函式不會改動數據)
5. 接收傳遞進來的參數,盡量以reference的方式傳遞(有例外須看狀況)
6. 返回值盡量以reference的方式來傳(不回傳local objects的情況下)
:::
---
## 7. 三大函數:複製建構子,複製賦值,解構子
> 使用string作為範例
> Reference: https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three
### Big Three, 三個特殊函數
```cpp=
class String
{
public:
String(const char* cstr = 0); // 建立建構子
String(const String& str); // 1. 複製建構子
String& operator = (const String& str); // 2. 複製賦值
~String(); // 3. 解構子
char* get_c_str() const { return m_data; }
private:
char* m_data; // 設置指標,指向字串空間
}
```
示意圖:
### ctor 和 dtor (建構子與解構子)
> new char初始值為'\\0'
```cpp=
String::String(const char* cstr = 0)
{
if (cstr) { // 判別是否有值
m_data = new char[strlen(cstr)+1]; // 最後在+1 為結束符號'\0'
strcpy(m_data, cstr);
}
else { // 未指定初始值
m_data = new char[1];
*m_data = '\0';
}
}
inline
String::~String()
{
delete[] m_data; // 之前是new一個array,因此這邊要刪除array []
}
```
另外,下方給出一個實例:說明如何創建這個類別
```cpp=
{
String s1(), // 使用建構子創建
String s2("hello"); // 使用"複製建構子"方式創建
String* p = new String("world"); // 創建一個pointer指向String Class
delete p; // 使用完後,記得要刪掉pointer內容
}
```
### class with pointer members 必須有 copy ctor 和 copy op=
:::warning
應當避免 淺複製(shallow copy)的發生,若無設定copy ctor 和 copy op=,編譯器將會使用預設的方式,會造成錯誤
:::
以下是錯誤範例,應盡量避免

### copy ctor (複製建構子)
> 以s1為藍本,創建對象 (深複製(deep copy))
```cpp=
inline
String::String(const String& str)
{
// 直接取另一個object的private(同類之間互為friend)
m_data = new char[ strlen(str.m_data) + 1 ];
strcpy(m_data, str.m_data);
}
////// in test
{
String s1("hello");
String s2(s1);
//String s2 = s1;
}
```
### copy assignment operator (複製賦值函式)
:::success
複製賦值要考慮到自我賦值的檢查
:::
```cpp=
inline
String& String::operator = (const String& str)
{
// ** 檢測自我賦值(self assignment) **
if (this == &str) // 不僅僅效率問題,也有可能防止出錯
return *this; // 下一節講解
delete[] m_data; // 1. 先殺掉自己
m_data = new char[ strlen(str.len) + 1 ]; // 2. 重新分配位置
strcpy(m_data, str.m_data); // 3. 複製
return *this; // 傳值
}
```
:::info
另外補充一點:
1. 接在typename後面的& (EX: ```const String& str```),指的是"以reference的方式接收"的意思 (reference)
2. 在變數前面的& (EX: ```this == &str```),指的是"取該變數的位址"的意思 (address of)
:::
### 一定要在operator= 中檢查是否self assignment

### output函數
```cpp=
#include <iostream.h>
ostream& operator << (ostream& os, const String& str)
{
os << str.get_c_str();
return os;
}
////// for test
{
String s1("hello");
cout << s1;
}
```
## 8. 堆積(heap)、堆疊(stack)與記憶體管理
### 所謂stack, heap
* **Stack**
* 是存在於某作用域(scope)的一塊內存空間(memory space)。例如當你使用函數,函數本身會形成一個stack用來放置它所接收的參數,以及回傳地址。
* 在函數本體(function body)內聲明的任何變量,其所使用的內存塊都取自上述的stack
* **Heap**
* 或所謂"system heap",是指由操作系統提供的一塊global內存空間,程序可動態分配(dynomic allocated)從中獲得若干區塊(blocks)
* 動態取得,使用new, delete的方式做操作
```cpp=
class Complex { ... };
...
{
Complex c1(1, 2); // c1 所占用的空間來自於stack
Complex* p = new Complex(3);
// Complex(3)是個臨時對象,其所占用的空間乃是以"new"
// 自heap動態分配而得,並且讓 p 指著。
}
```
### stack object的生命週期
```cpp=
class Complex { ... };
...
{
Complex c1(1, 2);
}
```
c1 便是所謂的"stack object",其生命在作用域(scope)結束之際跟著結束。
這種作用域內的object,又稱為auto object,因為它會被「自動」清除。
### static local objects 的生命週期
```cpp=
class Complex { ... };
...
{
static Complex c2(1, 2);
}
```
c2便是所謂的static object,其生命在作用域(scope)結束之後仍然存在。
解構子不會被調用,直到程式結束。
### global objects的生命週期
```cpp=
class Complex { ... };
...
Complex c3(1, 2);
{
...
}
```
c3便是所謂的global object,其生命在整個程式結束之後才會結束。可以把它視為一種static object,其作用域為「整個程式」
### heap objects的生命週期
```cpp=
class Complex { ... };
...
{
Complex* p = new Complex; // p 所指的便是heap object
...
delete p; // 它的生命它被delete之際就結束了
}
```
下面這個例子會造成記憶體流失(memory leak)的問題,因為作用域結束時,p所指的heap object仍然存在,但指針p的生命卻結束了,作用域之外也看不到p。
因此沒機會delete p
```cpp=
class Complex { ... };
...
{
Complex* p = new Complex;
} // 作用域結束,造成記憶體流失
```
:::success
有new一個值,就一定要搭配delete,否則會造成記憶體流失的問題
:::
### new: 先分配memory, 再調用ctor

2是一個轉型作用
在3中,因為建構子是成員函式,因此有隱藏字元this
### delete: 先調用dtor, 再釋放memory

### 動態分配所得的記憶塊(memory block), in VC

每一種class都分左右兩個,左邊為debug模式,右邊為release模式
紅色是cookie,紀錄儲存空間的大小,最後面的1指的是我這個空間被配置出去了(使用中)
> 字節等同於位元組byte;一個pointer 有四個位元組;一個double 有八個位元組;兩個連續的16進位數字為一個位元組
>

### array new 一定要搭配 array delete

## Summary
:::success
1. 欲建立含有指標的class類型,記得要重新定義"Big 3"三個特殊函數
2. 應當避免 淺複製(shallow copy)的發生,若無設定copy ctor 和 copy op=,編譯器將會使用預設的方式,會造成錯誤
3. 複製賦值要考慮到自我賦值的檢查
4. 有new一個值,就一定要搭配delete,否則會造成記憶體流失的問題
5. array new 一定要搭配 array delete
:::
## 10. Appendix: 類模板、函式模板與其他
### 靜態變數-static
> reference: [C/C++ 中的 static, extern 的變數](https://medium.com/@alan81920/c-c-%E4%B8%AD%E7%9A%84-static-extern-%E7%9A%84%E8%AE%8A%E6%95%B8-9b42d000688f)
> [C++ 變數的存放位置跟static三個用法](http://hatsukiakio.blogspot.com/2009/04/c-static.html)
>

* 靜態變數 static variables (static 出現在 class內)
* 靜態變數存放的位置是在.data中,並非區域變數所存放的stack中,與global variables類似
* 同一種class中的靜態變數為共用值,每個instance(每個建出來的相同類)都可以去使用這項變數
* 最經典的範例就是用來計數這個 class 總共生成了多少個 instance
```cpp=
class Account {
public:
static double m_rate; // 靜態變數宣告
static void set_rate(const double& x) { m_rate = x; }
};
double Account::m_rate = 8.0; // 可以在class宣告最後進行static變數的定義
// Implement - 調用static的兩種方法
int main() {
Account::set_rate(5.0); // (1) 透過object調用
Account a;
a.set_rate(7.0); // (2) 透過class name調用
}
```
### Singleton (單例)
> 參考之前講過的[程式碼](#Singleton-constructor-ctor-建構子函數被放在private區)
* 單例Singleton 設計模式
* 這個class只希望產生一個對象
* 以下是單例較為平常的寫法,此寫法會有個問題-若外界無須調用這個class,會浪費已經被創建的a
```cpp=
class A {
public:
static A& getInstance ( return a; ); // 對外的唯一窗口
setup() { ... }
private:
A(); // 將建構子放在private,因此外界無法透由創建的方式得到class A
A(const A& rhs);
static A a; // 只有一個 class A
}
// Implement
A::getInstance().setup();
```
以下是較好的單例寫法:
* Meyers Singleton
```cpp=
class A {
public:
static A& getInstance();
setup() { ... }
private:
A();
A(const A& rhs);
...
};
A& A::getInstance() // 當有人調用到他,a才會被創建,一旦創建就會存在
{
static A a;
return a;
}
// Inplement
A::getInstance().setup();
```
### Function template 函式模板
> 回顧之前[類模板](#class-template-模板簡介)的形式
* 函式模板
* 創建模板函數,在製作class時加上```template <class T>```的宣告
* 編譯器會對function template進行引數推導(argument deduction):
抓到函式 -> 檢查是否符合模板 -> 連結相關運算子 -> show出結果

### namespace 命名空間
> reference: https://openhome.cc/Gossip/CppGossip/Namespace.html
以 std 作為例子示範:
```cpp=
namespace std
{
...
}
```
以下為三種命名空間的使用方式:
#### using directive
```cpp=
#include <iostream.h>
using namespace std; // 直接宣告我下面的程式碼都使用這個命名空間
int main(){
cin << ...;
cout << ...;
return 0;
}
```
#### using declaration
```cpp=
#include <iostream.h>
using std::cout; // 宣告特定函式使用該命名空間
int main(){
cin << ...;
cout << ...;
return 0;
}
```
#### 每次使用函式每次都進行宣告 (Suggested)
```cpp=
#include <iostream.h>
int main(){
std::cin << ...;
std::cout << ...;
return 0;
}
```
## 11. 複合(Composition)與繼承(Inheritan)
### Composition(複合),表示has-a (class內有class a)- Adapter Pattern
* Composition
* 如圖,在class queue底下有一個class Sequence,這個Sequence又叫做deque
* deque功能較為完整,而queue功能較為簡單
* class queue 內部包含著class deque,並使用其功能與變數




### Inheritan(繼承),Composition by reference-Bridge Pattern

* 他也擁有物件,但是為pointer/reference,使用指針相連
* pointer to implementation
* 對於函數的繼承,子類繼承的是父類的調用權
### Inheritan(繼承), 表示is-a


## 12. 虛函數與多態
### Inheritan(繼承) with virtual function(虛函數)
> Reference:
> https://medium.com/theskyisblue/c-%E4%B8%AD%E9%97%9C%E6%96%BC-virtual-%E7%9A%84%E5%85%A9%E4%B8%89%E4%BA%8B-1b4e2a2dc373
> https://shengyu7697.github.io/cpp-virtual/
> About Abstrat Class and Intervace:
> https://www.cnblogs.com/oomusou/archive/2007/05/07/738311.html
> https://stackoverflow.com/questions/12854778/abstract-class-vs-interface-in-c
> https://www.tutorialspoint.com/cplusplus/cpp_interfaces.htm
* Class內函數分類:
* non-virtual function:
* 你不希望derived class 重新定義(override,覆寫)它
* 不能夠被改變,只能沿用
* virtual function:
* 你希望derived class重新定義(override,覆寫)它,且它是已經**有默認值**的。
* 可以被重新定義,也可以不用(這樣就會直接沿用default定義)
* pure virtual function:
* 你希望derived class一定要重新定義(override,覆寫)它,且它是**沒有被定義默認值**的。
```cpp=
class Shape{
public:
virtual void draw() const = 0; // pure irtual function
virtual void error(const std::string &msg); // (impure) virtual function
int objectID() const; // non-virtual function
...
}
class Rectangle: public Shape{ ... };
class Ellipse: public Shape{ ... };
```
### Inheritan(繼承) with virtual 應用-Template Method
* 如同windows作業系統,假設PowerPoint要進行開啟舊檔的動作
* 會經過幾個步驟: Check file name -> Search file -> Open file -> 在磁碟裡撈資料
* 程式碼可以表現如下:

* 在此有幾個重點:
1. 看最左邊,CMyDoc繼承CDocument
2. CDocument中,有個叫做Serialize()的函數,並沒有定義(設為虛函數),就像只創造一個模板一樣,留到後續再進行創造與定義。這樣的技巧是一種稱為**Template Method**的設計模式
3. 最右邊看到執行主程式,會先到被繼承的類中運行呼叫的相關函數
4. 等到執行到需要被定義的虛函數時,會再跑到繼承的函數尋找這個虛函數的定義
5. 繼續被繼承的函數,繼續執行
* 實際程式碼範例:

### Delegation(委託) + Inheritance(繼承) 應用-Observer Pattern
* 應用情境:重複開許多視窗,這些視窗都會傾聽同樣的動作,顯示相同的或相異的畫面(但所提取的資料都相同)


* 程式碼解釋:
* 類似於Qt中,[Model View Architecture](https://dangerlover9403.pixnet.net/blog/post/215257848-%5Bqt%E6%95%99%E5%AD%B8%5D-qt%E8%B6%85%E7%B0%A1%E5%96%AE%E6%95%99%E5%AD%B8day-3-(-model-,-view-))的架構
* 這樣的技巧是一種設計模式-**Observer Pattern**
* 使用者可以創建很多class去繼承Observer作為父類(一對多)
* Class Subject物件可以使用容器裝載繼承Observer的子物件們,進行統一管理(做同步更新)
* Class Observer 中,創建一個虛函數update進行資料更新。當物件(Subject)資料被進行修改時,會呼叫notify讓子物件們都同步做資料更新
## 13. 委託相關設計
### Delegation(委託) + Inheritance(繼承) 應用-Composite Pattern
> Reference: https://www.gushiciku.cn/pl/pPh1/zh-tw
>

### Delegation(委託) + Inheritance(繼承) 應用-Prototype Pattern

> 名詞符號解釋:
> ++下畫線++: static變數或函數
> 先寫obect名稱(:左邊),再寫type名稱(:右邊)
> -名稱: 代表private變數或函數
> +名稱 or 名稱: 代表public變數或函數
> #名稱: protect變數或函數
> 名稱(): 代表建構子
> 名稱(int, ...): 代表函數
* Prototype Pattern設計模式
* abstraction(抽象)以上,為一種形式、版型、藍本。可以讓主要的框架看到,進行操作
* abstraction(抽象)以上,為子類,在未來才會被派生下去
* 上面會準備空間,下面新生的類,會再將他的原型放上去
* 程式範例



## 14. 導讀
https://youtu.be/satNNEwsaDU
比前一個課程,學的更深入。
## 15. Conversion Function
### 轉換函數(conversion function)的使用方法
* 程式範例:
```cpp=
class Fraction
{
public:
Fraction(int num, int den=1)
: m_numerator(num), m_denominator(den) { }
operator double() const {
return (double)(m_numerator / m_denominator);
}
private:
int m_numerator;
int m_denominator;
}
// Inference:
Fraction f(3, 5);
double d = 4 + f; //調用operator double() 將f轉換為0.6
// 編譯器會先找"+"的運算子,若沒有,轉換f看看能否編譯過。
```
> 其中,operator那串function即為**conversion function**
* 語法特點:
* 轉換不能改變class內部的參數,因此通常需要加const
* 不需要寫上return type(返回類型)
### 其他範例
```cpp=
// Class
template <class Alloc>
class vector<bool, Alloc> // 這個class裡面接為boolean值
{
public:
typedef __bit_reference reference; // 代理,reference應為boolean值
protected:
reference operator[](size_type n){
return *(begin() + difference_type(n));
}
...
}
// In __bit_reference struct
struct __bit_reference {
unsigned int *p;
unsigned int mask;
...
public: //此為轉換函數
operator bool() const { return !(!(*p & mask)); }
}
```
---
## 16. Non-Explicit One Argument Constructor
### Argument vs. Parameter
> Reference: https://shengyu7697.github.io/cpp-parameter-argument/
* Argument(引數) vs. Parameters(參數)
* Parameter (參數) 是函式宣告 (或函式簽章) 裡的變數;Argument (引數) 是表示呼叫函式時所帶入的變數或數值。
* 影片中舉例:```Fraction(int num, int den=1)```的狀況下,我們可以說:Fraction函式中有兩個**參數**,但呼叫時只需要一個**引數**就夠了(因為另外一個已經有預設值)。
### non explicit one argument constructor
```cpp=
class Fraction
{
public:
Fraction(int num, int den=1)
: m_numerator(num), m_denominator(den) { }
Fraction operator+ (const Fraction& f) {
return Fraction(...);
}
private:
int m_numerator;
int m_denominator;
}
// Inference:
Fraction f(3, 5);
double d = f + 4; //調用non explicit ctor 將4轉換為Fraction
// 接著再調用operator+
```
* 特色:能夠將別種型別,透過non explicit的方式轉換為該種class的型別。(編譯器會自動調用協助轉換)
* 但若與conversion function合併寫在一起時,編譯器會出錯(多於一條路線可行),會釋出[Error] ambiguous
### explicit one argument constructor
> explicit: 明白、明確的意思
```cpp=
class Fraction
{
public:
explicit Fraction(int num, int den=1)
: m_numerator(num), m_denominator(den) { }
Fraction operator+ (const Fraction& f) {
return Fraction(...);
}
private:
int m_numerator;
int m_denominator;
}
// Inference:
Fraction f(3, 5);
double d = f + 4; //[Error] conversion form 'double' to 'Fraction' requested.
```
* 加上關鍵字explicit,說明編譯器不能自動幫忙轉換類別,需要使用者**明確定義**
* 通常在**建構子之前**
---
## 17. Pointer-like Classes
### Pointer-like Classes, 智能指針
```cpp=
template <class T>
class shared_ptr
{
public:
T& operator*() const
{ return *px; } //將所指的內容回傳
T* operator->() const
{ return px; }
private:
T* px;
long* pn;
}
// Foo 結構寫法
struct Foo
{
...
void method(void) { ... }
};
// Inference
shared_ptr<Foo> sp(new Foo);
Foo f(*sp);
sp->method(); //同px->method();
```
* 重點在於:```*```以即```->```操作符的重載。沒有例外,都是這樣寫的。
* ```->```得到的元素,需要**再接著```->```作用上去**
* 
### Pointer-like Classes, 迭代器(iterator)
* 迭代器作用也像智能指針一樣
* 但迭代器有許多運用,方便該「容器」可以做運算之用
* 舉```list```為例:

```cpp=
T& reference operator*() const
{ return (*node).data; }
T* pointer operator->() const
{ return &(operator*()); }
// Inference
list<Foo>::iterator ite;
...
*ite; //取得一個Foo物件
ite->method();
//意義為調用Foo::method();
//相當於(*ite).method();
//也等於(&(*ite))->method();
```
---
## 18. Function-like Classes
### Function-like Classes, 仿函數(函數對象)
```cpp=
template <class T>
struct identity : public unary_function<T, T> {
const T&
operator()(const T& x) { return x; }
};
template <class Pairs>
struct select1st : XXX {
const typename Pair::first_type&
operator()(const Pair& x) const
{ return x.first; }
};
...
// Inference
template <class T1, class T2>
struct pair {
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b)
: first(a), second(b) {}
...
};
```
* 重點在於改寫```()```操作符
* 標準庫中,仿函數都會繼承奇特的base classes
---
## 19. namespace 經驗談
https://www.youtube.com/watch?v=DgP-EbSpuSY
## 20. 類模板
https://www.youtube.com/watch?v=ALwnBsK_wAU
## 21. Funtion Template
https://www.youtube.com/watch?v=2LWbRVKOFUo
## 22. Member Template
https://www.youtube.com/watch?v=4-HRDl2hQ_A
## 23. specialization (特化模板)
https://www.youtube.com/watch?v=5COEXgHb25k
## 24. partial specilization (偏特化)
https://www.youtube.com/watch?v=VX-DfNwxqgA
## 25. 模板模板參數
https://www.youtube.com/watch?v=d6qrzDVn8T8
## 26. 關於C++標準庫
https://www.youtube.com/watch?v=AF3WHSc8h7Q
## 27. C++11 三種主題
https://www.youtube.com/watch?v=4-1-wT4t2Hs
## 28. Reference
https://www.youtube.com/watch?v=9AsMOrfRCkQ
reference 當宣告完成時,就無法再重新代表其他東西
## 29. 複合、繼承中的建構子與解構子
https://www.youtube.com/watch?v=vhOSeapZ03k
## 30. Vptr and Vtbl
https://www.youtube.com/watch?v=MysC48nh9yI
動態綁定:1.透過指針;2.指針向上轉型;3.虛函數 => Compiler會進行虛機制(virtual machanica...),進行動態綁定。
## 31. 關於this
https://www.youtube.com/watch?v=WShbnGNkHlg
## 32. 關於動態綁定
https://www.youtube.com/watch?v=qwswGhYZE4Q
(p) => 代表this pointer
## 33. 關於動態綁定
https://www.youtube.com/watch?v=WWbYbcIhtUI
## 34. 關於new delete
https://www.youtube.com/watch?v=I5KahB0XRY4
## 35. Operator new,operator delete
https://www.youtube.com/watch?v=yTxuNxYVDaY
## 36.
https://www.youtube.com/watch?v=B2z6YWL6xMs
## 37. 重载new,delete$示例
https://www.youtube.com/watch?v=EuIrt0dBZco
https://tw-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/comments.html
https://m-peko.github.io/craft-cpp/posts/different-ways-to-define-binary-flags/