# 計算機程式
[台大公開課](http://ocw.aca.ntu.edu.tw/ntu-ocw/ocw/cou/101S112/1/V/1)
## 硬體小筆記
Chapter 1
- ### Main Memory
- #### RAM(random access memory):
- 存取的時間與儲存位置的排序無關。
- 存取速度很快,相較於Secondary Storage Unit/ROM(read only memory)。
- 具揮發性: 斷電後儲存的資料會消失。
- #### DRAM(dynamic random access memory)
- 半導體記憶體,利用電容內儲存電荷的多寡儲存0與1。
- 現實中電晶體會漏電,會影響儲存內容的正確性,故須透過刷新來進行週期性充電(稱之為動態的原因)。
- #### SRAM(static random access memory)
- 只要維持通電的情況,不需要刷新也不會丟失儲存的內容。
- 常用於CPU當中的cache memory。
- 存取速度快,但是貴。
## Background Knowledge
### compile/ link/ executable file
---

---
- #### Windows System
- 順序:
- .cpp compile to .o (machine code)
- .o linking to .exe (executable code)
- 方法:
- Single File
- 一行指令完成
`g++ -o hello.exe hello.cpp`
- 分行完成
```
// Compile-only with -c option
g++ -c Hello.cpp
// Link object file(s) into an executable
g++ -g -o Hello.exe Hello.o
```
- note:
- -Wall: prints "all" Warning messages.
- -g: generates additional symbolic debuggging information for use with gdb debugger.
- Multiple File
- 一行指令
`g++ -o myprog.exe file1.cpp file2.cpp `
- 分行完成
```
g++ -c file1.cpp
g++ -c file2.cpp
g++ -o myprog.exe file1.o file2.o
```
- MakeFile
- 建立無附檔名的makefile
```
//makefile
all: hello.exe
hello.exe: hello.o
g++ -o hello.exe hello.o
hello.o: hello.cpp
g++ -c hello.cpp
clean:
rm hello.o hello.exe
```
- 使用指令:
`make
`
- 實際執行:
```
g++ -c hello.cpp
g++ -o hello.exe hello.o
```
- **注意事項**:
- 只會執行makefile第一行,然後根據需求往下找;故第一行需是all的資訊
- #### Unix System
- 順序:
- .cpp compile to .o (machine code)
- .o linking to 執行檔(無檔名) (executable code)
- 方法:
- Single File
- 一行指令完成
`g++ -o hello hello.cpp`
- 分行完成
```
g++ -c hello.cpp
g++ -o hello hello.o
```
- Multiple File
- 一行指令完成
`g++ -o myprog.exe file1.cpp file2.cpp `
- 分行完成
```
g++ -c file1.cpp
g++ -c file2.cpp
g++ -o myprog file1.o file2.o
```
- MakeFile
- 建立無附檔名的makefile
```
//makefile
all: hello
hello: hello.o
g++ -o hello hello.o
hello.o: hello.cpp
g++ -c hello.cpp
clean:
rm hello.o hello
```
- 使用指令:
`make
`
- 實際執行:
```
gcc -c hello.cpp
gcc -o hello hello.o
```
- **注意事項**:
- 只會執行makefile第一行,然後根據需求往下找;故第一行需是all的資訊
### Object Oriented Programming (OOP)
#### 特性
- 封裝
- 把物件的屬性跟方法包在一起,在內部的屬性跟方法定義完後,外部只能透過物件提供的介面去進行操作。可以避免外部的不當操作,在使用上也可以變得比較簡單,不需要去在意內部的實作。
- 繼承
- 提升程式的重用性、延展性,可以把一些共通性很高的類別定義在同個父類別,子類別可以繼承父類別共通的屬性,再根據子類別的一些特異性去定義自己的屬性與方法。
- 多型
- 用同一個介面來實現不同的方法。
- 包含overload(靜態)跟override(動態),同名的function根據接收者不同可以對同一事件做出不同回應。
- overload是指同樣function名稱透過輸入數量或類型不同,function會做不同的事情。
- override指的是子類別,在有宣告virtual的情況下,父類別同名的function可以直接改寫父類別的function,但是父類別跟子類別function的參數必須相同。
- overwrite指的是將父類別的function隱藏起來,(覆寫掉父類別的function),父類別跟子類別同名function的參數可以相同也可以不同。
- virtual function也是多型的一個實踐,也就是看接收者是誰再來決定實作內容。如果父類別跟子類別都有同一個function,在父類別的function加上virtual,在外部做運用的時候,只要透過父類別的pointer來指父類別跟子類別的物件,就能根據他們實際上的類別來實踐這個同名的function。
#### 優點
- 可重用性、延展性、彈性
## Array, Pointer and String
Chapter 6~8:
- ### Array
- 分配一段連續的儲存位置
- 宣告陣列的方法:
- 需要提供allocate的位置的大小
- 需要**類型**及**大小**等資訊
```
int arr[7];
int arr2[3]={1,2,3};
```
- 須注意的地方:
- 使用到一開始宣告的陣列以外的位置
- 如該位置存在且為變數,即可以變動它
```
int arr[3]={1,2,3};
arr[8] = arr[1] + arr[2];
```
- 將不想被變動的值設為常數
```
const int a = 5;
```
- 1D Array傳到function中
- pass by value
```
int a[5];
void printa(int a[]){...}
printa(a);
```
- pass by reference
```
int a[5];
void printa(int (&a)[5]){...}
printa(a);
```
- pass by address
```
int a[5];
void printa(int* a{...}
printa(a);
```
- ### Pointer
- 為一個儲存位置的地址,需要提供此位址指向的**類型**
- 須透過此地址更改或存取該位址當中的值
- 宣告指向的位置及存取值:
```
int a = 5;
int *p = &a;
cout << 'the value of variable a is' << a << endl;
cout << 'the pointer p is pointed to the address of a.'<< endl;
cout << 'the place of the pointer p pointed to stores the value of ' << *p << endl;
```
> Output:
> the value of variable a is 5
> the pointer p is pointed to the address of a.
> the place of the pointer p pointed to stores the the value of 5.
- 更改指向位置儲存的值:
```
int a = 5;
int *p = &a;
*p = 10;
cout << 'the value of variable a now is ' << a <<endl;
```
> Output:
> the value of variable a now is 10
- 須注意的事項:
- 清除pointer目前指向的位置,指向0或NULL皆可。
```
int *p = 5;
p = 0;
p = NULL;
```
- 宣告時可以與同類型的變數一併出現
```
int a, *x = &a;
```
- **非常重要: 勿與Reference(參考)搞混**
- Reference是一個**已經存在的變數**的**ailias(別名)**
- 易與位址搞混,當作位址時該位址的變數須先被宣告
```
int a, int &b = a;
cout << 'an integer variable a was defined, while b was not defined as a variable before: b was an ailias of variable a.' << endl;
int c, int d = &c;
cout << 'an integer variable c was defined: d was an integer storing the address of variable c now.' <<endl;
```
> Output:
> 整數變數a已定義,但b並未被定義成任何變數: b是變數a的別名/參考. (翻譯)
> 整數變數c已定義: d是一個整數變數,目前儲存變數c的位址。(翻譯)
- Reference的目的在於盡可能**節省空間**,減少在不必要的情況下新增一個新的變數。
```
int addNum(int a,int b){
return a+b;
}
int betterAddNum(int &a, int &b){
return a+b;
}
void main(){
int num1 = 5;
int num2 = 3;
cout << '1. with allocation of new variables a and b for function addNum <<endl;
cout << ' addNum(num1,num2) = ' << addNum(num1,num2) << endl;
cout << '2. instead of allocation of new variables a and b, just pass the value of variable num1 and num2 by creating their ailiases and calling by references.' >>endl;
cout << ' betterAddNum(num1,num2) = ' <<betterAddNum(num1,num2) << endl;
}
```
>Output:
> 1. 為了函式addNum,有分配位置給新的變數a及b(翻譯)
> addNum(num1,num2) = 8
> 2. 取代分配位置給新的變數a及b,建立num1及num2的別名,並透過呼叫參考的方式將它們的值直接傳入(翻譯)
> betterAddNum(num1,num2) = 8
- Reference 傳送的是該物件的別名,代表傳進去的其實就是那個物件,如更改那個物件的值,是**會改變該物件**的。
```
//main.cpp
//用比較混亂的寫法但比較好呈現,實際操作請把dog.cpp,dog.h分開
class Dog(){
public:
Dog& olderDog(Dog& dog){
dog.age += 1;
return dog;
}
Dog(int a){
age = a;
}
int getAge(){
return age;
}
private:
int age;
}
void main(){
Dog apple(10);
cout<<"apple's age = " << apple.getAge()<<endl;
Dog apple2 = apple.OlderDog();
cout<<"apple's age now = "<<apple.getAge()<<endl;
cout<<"the one return = "<<apple2.getAge()<<endl;
return;
}
```
>Output:
> apple's age = 10.
> apples age now = 11.
> the one return = 11.
- ### String
- 字符陣列也可用來表示字串,字串宣告必伴隨截斷符號(\0)
```
char c[] = "blue";
char d[] = {'b','l','u','e','\0'};
```
- 陣列名稱與pointer具相同功能
```
char color[5] = "blue";
char const *p = color;
char const *t = &color[0];
cout << "char color[3] is " << color[3] << " and *(p+3) is " << *(p+3) <<endl;
```
> Output:
> char color[3] is e and *(p+3) is e
- ### Vector
- Pass 2D vector into function
- 方法一: pass by value
`void passVector(vector<vector<int>> v){...}`
- 方法二: pass by reference
- 避免pass by value造成的copy and pass
`void passVector(vector<vector<int>>& v){...}`
## Classes and Data Abstraction
Chapter 9~10
- ### Classes
- 存取與修改權限: public, private, protected
- 宣告方法
```
class Dog{
public:
void setAge(int a){ age = a; }
void setGender(int g){ gender = g; }
int getAge(){ return age; }
int getGender(){ return gender; }
int fitness(){ return weight*age/1.495*(gender+0.45); }
Dog(int a,int g,int w){ age = a; gender = g; weight = w;}
private:
int age = 0;
int gender = 0; //girl,boy
int weight = 0;
}
```
- 拆分成header(.h)與implementation(.cpp)檔案:
- header
```
//dog.h
#ifndef DOG_H
#define DOG_H
class Dog{
public:
void setAge(int a);
void setGender(int g);
int getAge();
int getGender();
float fitness();
Dog(int a, int g, int w);
private:
int age = 0;
int gender = 0;
int weight = 0;
}
#endif
```
- cpp
```
//dog.cpp
#include "dog.h"
Dog::Dog(int a, int g, int w){
age = a;
gender = g;
weight = w;
}
void Dog::setAge(int a){
age = a;
}
void Dog::setGender(int g){
gender = g;
}
int Dog::getAge(){
return age;
}
int Dog::getGender(){
return gender;
}
float Dog::fitness(){
return age*weight/1.495*(gender+0.45);
}
```
- 在main.cpp如何使用class:
```
//main.cpp
#include "dog.h"
```
- extern 與靜態(static)用法
- extern:
- 令其他cpp file可以存取其他檔案中的特定變數
```
//main.cpp
#include "dog.h"
using namespace std;
void main(){
cout << "a = " << a << endl;
a = 0;
cout << "a = " << a << endl;
}
```
```
//dog.h
#ifndef DOG_H
#define DOG_H
extern int a;
void greeting();
#endif
```
```
//dog.cpp
#include "dog.h"
int a = 1;
void greeting(){
cout<< "hello its me."
}
```
- static(靜態)
- 存在時間與主程式(main)執行時間相同,該函式結束時仍保存著
```
int couting(){
static int counter = 0; //only initialized at the first time
return counter++;
}
```
- **作用域不變**,宣告於function內,可存取的位置仍是function內:防止不同檔案中相同變數名稱在link時出現錯誤
```
//a.h
#ifndef A_H
#define A_H
static int dds;
#endif
```
```
//b.h
#ifndef B_H
#define B_H
static int dds;
#endif
```
```
//main.cpp
#include "a.h"
#include "b.h"
......
```
```
//sh
g++ -c main.cpp //產生main.o
g++ -c a.cpp //產生a.o
g++ -c b.cpp //產生b.o
g++ -o main main.o a.o b.o //如果未加入"static": 錯誤產生,因為main.cpp裡面include a.h以及b.h,但當中有重複變數名稱dds
```
- **非常重要!! static 使用在class當中不屬於任何物件**
- 使用在class variable前:
- 此variable不屬於此class的任何object,即不屬於任何instance;為**整個class共用之變數**
- **初始化**的方法,**不可以在class宣告時做**,需要在class外面、main外面。
- 使用在class function前:
- 此function不屬於此class的任何object,即不屬於任何instance;為整個class**共用之函式**
```
#include <iostream>
using namespace std;
class Object {
public:
Object() {
++counter;
cout << "counter = " << counter << endl;
}
static int getCounter() { return counter; }
private:
static int counter;
};
int Object::counter = 0; // initializing the static int
int main() {
Object obj1;
Object obj2;
Object obj3;
cout << Object::getCounter() << endl;
return 0;
}
```
- constant(const) object:
- 只能呼叫const function,無法呼叫non-const function; **但是const function可以被const object以及non-const object呼叫!**
- **只能用member initializar**的方式創建物件並賦予初始值:
```
//constMember.cpp include header definition version
Class Dog{
public:
int get_weight() const;
Dog(int a,int g); //constructor using member initializer
private:
int age;
int gender;
}
int Dog::get_weight() const { return a+g/g*2;}
Dog::Dog(int a,int g) : age(a),gender(g){} //constructor using member initializer
```
```
//main.cpp
#include "constMember.cpp"
using namespace std;
void main(){
//member initializer=
//CLASS_NAME INSTANCE_NAME(first_value,second_value );
const Dog doggy(5,0); //const object
Dog kitty(3,1); //non-const object
doggy.get_weight();
kitty.get_weight();
//使用pointer創建物件的呼叫方法
Dog* dog_ptr = new Dog(10,1);
(*dog_ptr).get_weight();
dog_ptr->get_weight();
}
```
- **一般 const 用法**:
- 基本使用:
`const int a = 10; //不可修改a的值`
- 指標使用:
```
const int* ptr; //不可修改ptr指向的內容
int* const ptr; //不可修改ptr指向的位置
const int* const ptr; //指向的內容、指向的位置都不可修改
```
- 回傳使用:
```
const int foo(); //函式外部不可修改回傳的值
```
- **constant(const) member function** vs return const object:
- const member function **無法改動成員屬性**
```
//passenger.h
class Passenger{
public:
int get_age();
const Passenger get_nextSeats(); //return回去的值是const
int get_bus_number() const; //member function是const,即此函式不能改動成員屬性
private:
...
}
```
- **須注意!!!的std結構operator:**
- std::map中的$[]$與**at**差異:
- []: 確認輸入key是否存在而返回,不存在會**insert**這個key進去;在const member function**不可以使用**
- **at**: 確認輸入key是否存在而返回,不存在會throw exception;在const member function中**可以使用**
- **兩個classes的object互call的極端狀況**
- 解法一
- 使用header file, cpp file來儲存各自的程式碼
- **不要互相於header file include對方**,會造成程式從A->B,又從B->A,但A已經被執行過,導致B無法參考A。
- **依照實作時參考的順序,來include在header file**;而cpp當中一般是include自己的header檔,但自己的header檔無包含對方的header檔,則**需在cpp內include以知道如何實作**。
```
main.cpp
#include "A.h"
#include "B.h"
...
```
```
A.h
#include "B.h"
...
```
```
B.h
...
```
```
A.cpp
#include "A.h"
...
```
```
B.cpp
#include "A.h"
#include "B.h"
```
- 解法二
- 共同放在一個source cpp,使用**前置宣告+動態配置記憶體**(pointer to class object / vector of class object),不然compiler不知道要**預留多少空間**,且可能會報錯無"對應的建構子"。
```
main.cpp
class Dog;
class Cat
{
private:
int id;
string name;
Dog* friend; // 全部Dog* pointer可抽換成vector<Dog>
public:
Cat(int i, string n, Dog* f);
Dog* get_friend();
}
class Dog
{
private:
int id;
string name;
Cat* Cat; // 全部Cat* pointer可抽換成vector<Cat>
public:
Dog(int i,string n, Cat* f);
Cat* get_friend();
}
```
## Operator Overloading
Chapter 11~12
- ### Function Overloading
- function 名稱相同,但是作得內容不同
- 考量:
- 輸入引數(parameter)數量
- 輸入引數(parameter)種類
- 輸入引數(parameter)順序
- ### Operator Overloading
- 不能更改運算元(operant)的數量
- 只能使用已存在的operator
- 一些無法overloading的運算子: condition operator(?:),address(&),...etc
- 一些系統會自己預設的運算子: assignment(=),reference(&),comma(,),不須特別做。
- assignment(=):
- 如未overload, class object之間會直接用copy的方式->創建一個物件,把每個屬性照抄過來。
- 只能利用member function去做overload.
- copy constructor:
```
Dog dog1(10,2,10.5);
Dog dog2(dog1); //copy constructor
```
- operator+ , <, > overloading:
```
class Dog{
public:
Dog(int a){
age = a;
}
int getAge(){
return age;
}
Dog operator+ (Dog dogB){ //operator add overloading
return Dog(age + dogB.age);
}
bool operator> (Dog dogB){ //operator add overloading
return age > dogB.age;
}
bool operator< (Dog dogB){ //operator add overloading
return age < dogB.age;
}
private:
int age;
}
void main(){
Dog dog1(10);
Dog dog2(20);
cout<<"dog 1 + dog 2 = "<<(dog1+dog2).getAge()<<endl;
return;
}
```
> Output:
> dog 1 + dog 2 = 30
- **須注意!!!****std.h**中的必須做operator overloading**特例**:
- 如**map與set**等**ordered** structure
- 故當儲存在map、set當中的是class object時,在進行insert等動作時,需要進行**排序**(key的**比較**等)
- 故需針對該class做 **>、<** 等運算子做**operator overloading**
```
#include "passenger.h"
using namespace std;
std::map<int,Passenger> passenger_list;
Passenger p1(10);
passenger_list[10] = p1; //insert需要排序比較
```
## Inheritance
Chapter 13
- ### 名詞解釋
- **Base** Class vs **Derived** Class
- base: 原先就存在的class,比較general。
- derived: 比較specific,繼承base class的特性(是base class的object),但可以有自己獨立的一些特性。
- **Direct** Base Class vs **Indirect** Base Class
- direct base: 你爸媽,直系繼承的第一個class
- indirect base: 你阿公阿嬤等,直系繼承但是好幾層以上的class
- **Single** Inheritance vs **Multiple** Inheritance
- single: 只繼承一個base class
- multiple: 繼承多個base class,校長同時是"老師"也是"管理者"
- ### **Inheritance Mode**
- public / private / protected inheritance
```
class Animal{
public:
void set_name(string n){ name=n; }
private:
string name;
protected:
string weight;
class Dog: public Animal{ //public inheritance
public:
void bark(){}
private:
string barksound;
}
class Cat: private Animal{ //private inheritance
public:
void meow(){}
private:
string meowsound;
}
class Bird: protected Animal{ //protected inheritance
public:
void fly(){}
private:
string flysound;
}
}
```
- public/private/protected inheritance 存取權限
```
class A{
public:
method_public;
private:
method_private;
protected:
method_protected;
}
class B: public A{
// method_public: public
// method_private: 不可存取
// method_protected: protected
}
class C: private A{
// method_public: private(可於內部呼叫,不可於外部呼叫)
// method_private: 不可存取
// method_protected: private(可於內部呼叫,不可於外部呼叫)
}
class D: protected A{
// method_public: protected(可於內部呼叫但有接收者,不可於外部呼叫)
// method_private: 不可存取
// method_protected: protected(可於內部呼叫但有接收者,不可於外部呼叫)
}
class E: A{ //默認private inheritance
// method_public: private(可於內部呼叫,不可於外部呼叫)
// method_private: 不可存取
// method_protected: private(可於內部呼叫,不可於外部呼叫)
}
```
- 須注意: derived class也**無法存取**base class的**private member**
- 如果是public繼承:
- 派生類別與外部**可直接存取**基類**public function**
- 派生類別與外部**無法存取**基類的**private function**
- **派生類別內部可以直接存取**基類的**protected function**,但若無提供介面給外部,**外部是不可直接存取**基類的protected function
- 如何提供介面?
- 在派生類別建立public function,外部透過此public function可以存取protected function/variables
- **建構子及解構子順序**
```
class A{
private:
int age;
B b;
C c;
}
class B{}
class C{}
class D: public A{}
A* a = new A();
delete a;
D* d = new D();
delete d;
```
> 順序:
> 建構B->建構C->建構A
> 解構A->解構C->解構B
> 建構B->建構C->建構A->建構D
> 解構D->解構A->解構C->解構B
```
class A{
public:
A(int k){ age = k; }
private:
int age;
}
class B: public A
{
public:
B(int a, int b):A(a){ cc = b; }
private:
int cc;
}
B* b = new B(27,4);
delete b;
```
> 順序:
> 建構A->建構B
> 解構B->解構A
- ### 重要!!! **Base and Derived Class Behavior**
```
#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
class Base
{
public:
Base() {
my_name = 10;
key = 'a';
cout<<"create base," << endl;
}
~Base() { cout << "destroy base," << endl; }
void f1() { cout<<"base f1," << endl; }
virtual void f2() { cout<<"base f2" << endl; }
private:
int my_name;
char key;
};
class Derived : public Base
{
public:
Derived() {
kk = "abc";
cout << "create derived," << endl;
}
~Derived() { cout << "destroy derived"<<endl; }
void f1() { cout << "derived f1," << endl; }
virtual void f2() { cout << "derived f2" << endl; }
void f3() { cout << "derived specific function" << endl; }
private:
string kk;
};
int main()
{
Base* bp = new Base(); //base obj
cout << "---" << endl;
Base* bd = new Derived(); //base obj with override
cout << "---" << endl;
Derived* dr = new Derived(); //derived obj
cout << "---" << endl;
Base* d = bd; //base -> base
Base* b = dr; //derived -> base : slicing
cout << "---" << endl;
//base->derived : will cause problem:
//Derived* d = bd; Derived* d = bp;
bp->f1();
bp->f2();
bd->f1();
bd->f2();
//bd->f3() : bd is base obj override by derived : no f3 function
delete bp;
cout << "---" << endl;
delete bd;
cout << "---" << endl;
delete dr;
cout << "---" << endl;
return 0;
}
```
- #### **輸出與結論**

- #### **建立、初始化:**
- 情況一: **以Base pointer指向新配置的Derived空間**:
- Base* bd = new Derived();
- 建立一個derived obj , **constructor : base->derived**(根據new後面的class)
- slicing 成一個base obj,override改寫f2()
- 不具有f3()這個derived obj才有的function
- 情況二: **Derived 透過slicing跟override可以初始化 Base,反之不行:**
- **1. Derived 透過slicing跟override可以初始化 Base Obj**:
- ex1. Base* b = bd;
- ex2. Base* b = dr;
- b會被視作指向一個slicing後的base obj,但是由於override改寫了f2()
- **2. 無法透過 Base Obj 初始化 Derived Obj:**
- ex1. (compile error!) Derived* d = bd;
- ex2. (compile error!) Derived* c = dr;
- #### **刪除、釋放記憶體:**
- 視作釋放一個base obj, destructor: base
- **pointer是指向Base obj的**
- ex1. delete b;
- ex2. delete bd;
- 視作釋放一個derived obj, destructor: derived -> base
- **pointer是指向Derived obj的**
- delete dr;
## Polymorphism
Chapter 14
- ### Polymorphism:
- 定義:
- 根據接收者是誰決定實際上執行的行為
- 條件須三項吻合:
- Inheritance
- Overloading
- Overriding
- ### **Virtual Function**:
- 用在polymorphism,會加在base class中,不知道明確如何implement的function上
- 實用此情境時,使用**base class的pointer**來導向base class以及derived class
```
class Operate{
public:
virtual void press(){
cout<<"按下開關。"<<endl;
}
class SW1: public Operate{
public:
void press(){
cout<<"按下101大樓內電梯裡的開關"<<endl;
}
}
class SW2: public Operate{
public:
void press(){
cout<<"按下101大樓內頂樓陽台的開關"<<endl;
}
}
void turnoff(Operate *Q1){ //一定要用pointer或reference喔!
Q1->press();
}
Operate Q1;
SW1 s1;
SW2 s2;
turnoff(&Q1); // base class
turnoff(&s1); // derived class 1
turnoff(&s2); // derived class 2
}
```
> Output:
> 按下開關。
> 按下101大樓內電梯裡的開關
> 按下101大樓內頂樓陽台的開關
- 一旦有pure virtual的function存在,該class即是一個抽象class,不可有該class的instance存在。
- ### Casing
- Upcasting vs Downcasting
- Upcasting: 把derived class obj指派(assign)給base class obj,但有slicing problem,即遺失derived class才有的特性(善用virtual function避免輸出遺失的特性)
```
class Pet{}
class Dog: public Pet{}
Pet pet;
Dog dog;
pet = dog; // upcasting with slicing
```
- Downcasting: 把base class指派給derived class,僅允許使用在pointer+dynamic casting的時候
```
class Pet{}
class Dog: public Pet{}
Pet pet = new Dog();
Pet p = new Pet();
Dog dog = new Dog();
//correct one
Dog d = dynamic_cast<Dog*>pet; // downcasting should with dynamic_cast
//error cases
Dog d = pet; // error without dynamic_cast
Dog c = dynamic_cast<Dog*>p; //error because the object p point to is actually a Pet class
```
