# 程式設計Ⅱ【筆記ⅡⅠ】 * [name=Ivy Lin] * [筆記Ⅰ](https://hackmd.io/lvLLSXxoTo6hLxpEyBIJbQ) * [筆記ⅠⅠ](https://hackmd.io/ukBiB1VJTB-T5T4c_uAA3g) * [//筆記Ⅳ](https://hackmd.io/Ts0lnTMpQgGPGw7cvc3X-A) ## 第八週 < *2023.10.31* > * ***standard library namespace*** * *#include <iostream>* * *using namespace std;* * *setprecision();* //設定精準度(double小數點後幾位) * *#include<algorithm>* //for_each 的標頭檔 * *#include<iomanip>* //設定cout格式的標頭檔 * *#include<functional>* //可以使用function這個container來宣告函數的變數 * 宣告例子 => *void print(function<int(double,double)> f);* //function 的回傳值是int, 傳入值是兩個double * *#include<math.h>* //數學運算值 Ex.fabs(); ->取絕對值 * ***string*** 資料型態 * 可以使用'+'來連接字串 * *string* 相關函數 => *s.length()* 計算字串長度 => *s.clear()* 清空字串 => *s.empty()* 查看字串是否為空 * ***auto 好用的 type inference*** * ***complex 資料型別*** //實數、虛數 * ***允許定義兩個名字相同但長相不同的function*** * ***Range-based for loop*** * *vector < type > v_name* * *standard library 裡面定的 container* * *vector.push_back(value);* //將value丟到vector中 * *vector.begin()* //vector開頭 * *vector.end()* //vector結尾 * *for(const auto& i:v)* //特殊寫法 * *setw(num)* //一個輸出設成幾個字元寬度 * ***Reference &*** * 幫變數取別名(效能等同C語言的指標) * 型別宣告方式 => *type&* * ***Lambda functions*** * 僅需寫"[]"作為函數名稱 * "[]"內要填寫function多用的值(或變數) ```clike= //Example for each(v.begin(), v.end(), [](auto& n){ n+=7; } ); ``` * ***Class 物件導向設計*** * 成員預設是*private* //不可被外部使用 * *public*區塊 //可以開放給外部使用 ```clike= //Example class complex{ private: double re; double im; public: // constructor 寫法 //class 名字(傳入參數): 初值設定 {函式內部程式碼} //class 名字(傳入參數) {函式內部程式碼} complex(double r,double i): re{r},im{i} {} complex(double r): re{r}, im{0} {} complex(): re{0},im{0} {} double real() const //加上 const ->不讓外部函示改動(cpp會辨識有const的函示,使重新定義的宣告失效) { return re; } double real(double d) { re=d; } complex& operator+=(complex z) //定義 complex 間的 "+=" //compiler會把operator拔掉剩下+= { re+=z.re,im+=z.im; return *this; //特殊指標=>指向當前處理的物件 } //宣告class的朋友 friend std::ostream & operator<<(std::ostream& os, const complex& a); }; //朋友的宣告 ostream& operator<<(ostream& os, const complex& a) { if (a.im>0) os << a.re << "+" << a.im << "i"; else if (a.im<0) os << a.re << a.im << "i"; else os << a.re; return os; } complex v{2.0}; //宣告一個complex v初值為 2.0+0i ``` ## 第九週 < *2023.11.7* > ### 實作一個 Rational class ```clike= #include <iostream> #include <iomanip> #include <math.h> #include <functional> #include <algorithm> using namespace std; // define class Rational { private: int number; int denom; public: // 備註:分號要拿掉 Rational() : number{0}, denom{1} { cout << "call default constructor\n"; } Rational(int n) : number{n}, denom{1} { cout << "call Rational(n)\n"; } Rational(int n, int d); // Rational(int n, int d) : number{n}, denom{d} {cout << "call Rational(n,d)\n"}; }; // global Rational::Rational(int n, int d) : number{n}, denom{d} { cout << "call Rational(n,d)\n"; } // function // main int main() { Rational a; Rational b(3); Rational c(4, 5); return 0; } ``` * 結構體 class 的一些簡介和實作 ```clike= #include <iostream> using namespace std; class Cwin { public: int weight; int length; // 建構函數(名字與結構體名稱相同,無返回型別->通常用來初始化) Cwin() : weight(0), length(0) {} Cwin(int x, int y) : weight(x), length(y) {} // 成員函數 space() { return weight * length; } // 自定義操作符 // this是當前對象的指標(一個代號),因此使用指標取值方式 // const可以保護被引用的對象不在函數內被更改值 //"&"在這邊是類似指標的用法(引用原本的函數而不是另外複製一份) Cwin operator+(const Cwin &other) const { Cwin result; result.x = this->x + other.x; result.y = this->y + other.y; return result; } }; int main() { Cwin x1; // Cwin x2(10, 20); x1.weight = 5; x1.length = 10; cout << "x1 space =" << x1.space() << endl; cout << "x2 space =" << x2.space() << endl; // 使用自定義的加法 Cwin sum = x1 + x2; cout << "sum x1,x2=" << sum << endl; return 0; } ``` //分辨使用const和'&'的時機 * const : 不想改動原始值,避免作出規範外舉動設的安全值 * & : 當函數會需要取用傳入變數的值,或是需要回傳/更動傳入變數值的時候會使用 ### 前情提要 #### *access control* * 一個 class 的 member 可以分成 * private ->只有同一個 class 的其他 member functions,或是該 class 的 friends 才能使用。 * protected ->只有同一個 class 的其他 member functions,或是該 class 的 friends,或是 derived classes 的 member functions 才能使用。 * public ->大家都可以用。 繼承的時候,在 class 名稱後面可以用 : * *public base_class_name* * *: protected base_class_name* * *: private base_class_name* 的形式,來指定繼承而來的 public 和 protected functions,要放在自己的哪個區域。 #### *virtual function* * 用來達到 *run-time polymorphic type* 的效果 (要搭配 pointers 或 references) * Compiler 通常是利用所謂的 virtual function table (vtbl) 來記錄指標,透過指標指向對應的 virtual functions。 * 一個 class 只要包含了任何 *pure virtual function*,就是一個 *abstract class*。Abstract class 不能產生物件,只能當作其他 classes 的 interface。 ```clike= #include <iostream> #include <vector> namespace shapes { using namespace std; struct Point { int x; int y; Point(int a, int b) : x{a}, y{b} { } }; class Shape { public: virtual Point center() const =0; // pure virtual function virtual void shift(Point dxy) =0; virtual void rotate(int angle) =0; virtual void draw() =0; virtual ~Shape() {} }; class Rectangle; class Circle : public Shape { public: Circle(Point p, int rr) : c{p}, r{rr} { } Point center() const override { return c; } void shift(Point dxy) override { c.x += dxy.x; c.y += dxy.y; } void rotate(int ) override { } void draw() override { cout << c.x << " " << c.y << " " << r << "\n"; } friend bool bounding(Rectangle &rec, Circle &cir); private: Point c; int r; }; class Rectangle : public Shape { public: Rectangle(Point p1, int wid, int hei) : ul{p1}, w{wid}, h{hei} { } Point center() const override { return Point(ul.x+w/2, ul.y+h/2); } void shift(Point dxy) override { ul.x += dxy.x; ul.y += dxy.y; } void rotate(int ) override { } void draw() override { cout << ul.x << " " << ul.y << " : "; cout << w << " " << h << "\n"; } friend bool bounding(Rectangle &rec, Circle &cir); private: Point ul; int w, h; }; void move_all(vector<Shape*>& v, Point to) { for (auto p : v) p->shift(to); } void rotate_all(vector<Shape*>& v, int angle) { for (auto p : v) p->rotate(angle); } void draw_all(vector<Shape*>& v) { for (auto p : v) p->draw(); } bool bounding(Rectangle &rec, Circle &cir) { return (cir.c.x - cir.r)>=(rec.ul.x) && (cir.c.x+cir.r)<=(rec.ul.x+rec.w) && (cir.c.y - cir.r)>=(rec.ul.y) && (cir.c.y+cir.r)<=(rec.ul.y+rec.h); } } // namespace shapes int main() { using namespace shapes; //Shape s; // no objects of an abstract class can be created. Circle c1 {Point{3,2},3}; Circle c2 {Point{2,5},4}; Circle c3 {Point{-2,-3},5}; Rectangle r1 {Point{-3,-1},10,10}; vector<Shape*> cp {&c1, &c2, &c3, &r1}; cout << "Three circles:\n"; draw_all(cp); cout << "Shifted by (5, 10)\n"; move_all(cp, Point(5,10)); draw_all(cp); cout.setf(ios::boolalpha); // set format for bool cout << bounding(r1, c1) << endl; // print true or false instead of 1 or 0 cout << bounding(r1, c2) << endl; cout << bounding(r1, c3) << endl; } ``` ## 第十週 < *2023.11.14* > > *MINI PROJECT DEMO* ## 第十一週 < *2023.11.21* > ```clike= #include <iostream> #include <memory> #include <cstdlib> using namespace std; template<typename T> class List { private: struct Node { T val; shared_ptr<const Node> next; Node(T v, const shared_ptr<const Node>& n): val{v}, next{n} { } }; shared_ptr<const Node> head; explicit List (const shared_ptr<const Node> & nodes) : head{nodes} { } public: List(): { } //head{nullptr} done by shared_ptr List(T val, const List & tail): head{make_shared<Node>(val, tail.head)} { } bool isEmpty() const { return (head == nullptr); } T car() const { if (isEmpty()) exit(EXIT_FAILURE); return head->val; } List cdr() const { if (isEmpty()) exit(EXIT_FAILURE); return List(head->next); } void show() const { if (isEmpty()) std::cout << ".\n"; else { std::cout << car() << "->"; cdr().show(); } } }; template <typename T> List<T> cons(T val, List<T> tail) { return List<T>{val, tail}; } template<typename S, typename T, typename F> List<S> mapl(F f, List<T> lst) { if (lst.isEmpty()) return List<S>(); else return List<S>(f(lst.car()), mapl<S>(f, lst.cdr())); } template<typename T, typename P> List<T> filter(P p, List<T> lst) { if (lst.isEmpty()) return List<T>(); else { if (p(lst.car())) { return List<T>(lst.car(), filter(p, lst.cdr())); } else { return filter(p, lst.cdr()); } } } template<typename S, typename T, typename F> S foldr(F f, S accumul, List<T> lst) { if (lst.isEmpty()) return accumul; else return f(lst.car(), foldr(f, accumul, lst.cdr())); } template<typename S, typename T, typename F> S foldl(F f, S accumul, List<T> lst) { if (lst.isEmpty()) return accumul; else return foldl(f, f(accumul, lst.car()), lst.cdr()); } template<typename T, typename F> void foreach(F f, List<T> lst) { if (!lst.isEmpty()) { f(lst.car()); foreach(f, lst.cdr()); } } template<class T> void print(List<T> lst) { foreach([](T v) { cout << v << "->"; }, lst); cout << "."; } template<typename T> List<T> concat(const List<T> a, const List<T> b) { if (a.isEmpty()) return b; return List<T>(a.car(), concat(a.cdr(), b)); } template<typename T> T findmax(const List<T> a) { return foldl([](T acc, T x){return (acc>x) ? acc : x;}, a.car(), a); } List<int> qqsort(const List<int> a) { if (a.isEmpty()) return a; int piv = a.car(); List<int> le = qqsort(filter<int>([=](int x){return piv>x;}, a.cdr())); List<int> ri = qqsort(filter<int>([=](int x){return piv<=x;}, a.cdr())); return concat<int>(le, cons(piv, ri)); } int main() { List<int> l; List<int> n = cons(4, cons(5, cons(6, cons(7, cons<int>(8, l))))); l.show(); n.show(); auto m0 = mapl<double>([](int i){return i*0.5;} , n); // List<double> m0.show(); n.show(); auto m = mapl<int>([](int i){return i+1;} , n); // List<int> m.show(); List<string> s = cons("abc"s, cons("defg"s, cons("hijkl"s, List<string>()))); s.show(); auto s_len = mapl<size_t>([](string r){return r.size();}, s); s_len.show(); m = filter<int>([](int i){ return i%2==0;}, n); m.show(); s = filter<string>([](string r){ return r.size()>4;}, s); s.show(); cout << foldl([](int acc, int i){return acc+i;}, 0, m) << endl; print(m); // or print<int>(m); cout << endl; List<List<int>> ll; auto mm = cons(m, cons(n, ll)); // List<List<int>> foreach([](List<int> l) { cout << "["; print(l); cout << "]" << "->";}, mm); cout << endl; auto g = concat(n, m); //List<int> g.show(); cout << findmax(g) << endl; List<int> ns = cons(9, cons(10, cons(6, cons(5, cons(4, cons(8, cons(7, l))))))); cout << "Before: "; ns.show(); ns = qqsort(ns); cout << "After: "; ns.show(); } ``` * 這個C++程式定義了一個基本的函數式風格鏈表實現,展示了各種列表操作,包括映射、過濾、折疊、串聯和快速排序。 * List 類別: > List 類別是一個泛型的鏈表實現。 > 鏈表中的每個節點由 Node 結構表示,包含一個值 (val) 和指向下一個節點的共享指針 (next)。 > 列表本身由指向頭節點的共享指針 (head) 表示。 * 建構子: > 有兩個建構子:一個默認建構子,初始化一個空列表,以及一個建構子,接受一個值和另一個列表,以在前端創建具有給定值的新列表。 * 基本列表操作: > isEmpty(): 檢查列表是否為空。 > car(): 返回列表的第一個元素。 > cdr(): 返回一個新列表,不包含第一個元素。 > show(): 印出列表的元素。 * 列表操作 (map、filter、fold、foreach、print、concat、findmax): > mapl: 對列表的每個元素應用一個函數,生成一個新列表。 > filter: 根據一個預測函數過濾列表的元素。 > foldr 和 foldl: 使用二元函數在列表上執行右折疊和左折疊(累加)。 > foreach: 對列表的每個元素應用一個函數。 > print: 印出列表的元素。 > concat: 串聯兩個列表。 > findmax: 找到列表中的最大元素。 * qqsort (鏈表的快速排序): > qqsort: 實現了鏈表的快速排序算法。 * 主函數: > 創建並操作整數和字符串列表,使用定義的操作。 > 演示了映射、過濾、折疊、打印、串聯和快速排序的使用。 * 這個程序展示了在C++中使用模板和Lambda函數來處理通用類型,並為鏈表操作提供函數式風格的接口,呈現了函數式編程的概念。