{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[{"file_id":"1AB3RNlLfkZBSZKu6_Wh20CkIpbxfJIve","timestamp":1663461789208}],"collapsed_sections":[],"authorship_tag":"ABX9TyO55K0r4SqcldvjcKpyEEhz"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"},"gpuClass":"premium"},"cells":[{"cell_type":"markdown","source":["#計算機程式設計二\n","#第十週上課內容\n","## Derived Classes, Abstract Classes\n","\n","這份講義想要解釋 base class (superclass) 和 derived classes (subclasses)。\n","\n","我們從 \"Stroustrup, Bjarne (2013-07-10). The C++ Programming Language (4th Edition)\" 書中，節錄關於這個主題需要知道的幾個重點。\n"],"metadata":{"id":"9xoK4OIjIfZA"}},{"cell_type":"markdown","source":["### 關於 virtual function\n","* 用來達到 run-time polymorphic type 的效果 (要搭配 pointers 或 references)\n","* 作者的話: \"By default, a function that overrides a virtual function itself becomes virtual. We can, but do not have to, repeat virtual in a derived class. I don’t recommend repeating virtual. If you want to be explicit, use override.\"\n","* Compiler 通常是利用所謂的 virtual function table (`vtbl`) 來記錄指標，透過指標指向對應的 virtual functions。\n","* 作者的話: \"If a class has a virtual function, it needs a virtual destructor.\"\n","\n","### 關於 pure virtual function 和 abstract class\n","* 一個 class 只要包含了任何 pure virtual function，就是一個 abstract class。Abstract class 不能產生物件，只能當作其他 classes 的 interface。\n","\n","### 關於 access control\n","一個 class 的 member 可以分成 `private` `protected` `public`\n","* 如果是 `private`、則只有同一個 class 的其他 member functions，或是該 class 的 friends 才能使用。\n","* 如果是 `protected`：則只有同一個 class 的其他 member functions，或是該 class 的 friends，或是 derived classes 的 member functions 才能使用。\n","* 如果是 `public`: 大家都可以用。\n","* 繼承的時候，在 class 名稱後面可以用  `: public base_class_name` 、`: protected base_class_name` 、 `:private base_class_name` 的形式，來指定繼承而來的 public & protected functions，要放在自己的哪個區域。\n","* 詳細的整理可參考 https://www.programiz.com/cpp-programming/public-protected-private-inheritance\n","\n"],"metadata":{"id":"05G1Fqg6GRZX"}},{"cell_type":"markdown","source":["底下的例子涵蓋上述概念。\n","\n"],"metadata":{"id":"azEB13vJtHte"}},{"cell_type":"code","source":["%%writefile E10_01.cpp\n","#include <iostream>\n","#include <vector>\n","\n","namespace shapes {\n","using namespace std;\n","struct Point\n","{\n","\tint x;\n","\tint y;\n","\tPoint(int a, int b) : x{a}, y{b} { }\n","};\n"," \n","class Shape \n","{\n","public:\n","\tvirtual Point center() const =0; // pure virtual function\n","\tvirtual void shift(Point dxy) =0;\n","\tvirtual void rotate(int angle) =0;\n","\tvirtual void draw() =0;\n","\tvirtual ~Shape() {}\n","};\n"," \n","\n","class Rectangle;\n","class Circle : public Shape\n","{\n","public:\n","\tCircle(Point p, int rr) : c{p}, r{rr} { }\n","\tPoint center() const override\n","\t{\n","\t\treturn c;\n","\t}\n","\tvoid shift(Point dxy) override\n","\t{\n","\t\tc.x += dxy.x;\n","\t\tc.y += dxy.y;\n","\t}\n","\tvoid rotate(int ) override { }\n","\tvoid draw() override\n","\t{\n","\t\tcout << c.x << \" \" << c.y << \" \" << r << \"\\n\";\n","\t}\n","\tfriend bool bounding(Rectangle &rec, Circle &cir);\n","private:\n","\tPoint c;\n","\tint r;\n","};\n","\n","class Rectangle : public Shape\n","{\n","public:\n","\tRectangle(Point p1, int wid, int hei) : ul{p1}, w{wid}, h{hei} { }\n","\tPoint center() const override\n","\t{\n","\t\treturn\n","\t\t\tPoint(ul.x+w/2, ul.y+h/2);\n","\t}\n","\tvoid shift(Point dxy) override\n","\t{\n","\t\tul.x += dxy.x;\n","\t\tul.y += dxy.y;\n","\t}\n","\tvoid rotate(int ) override { }\n","\tvoid draw() override\n","\t{\n","\t\tcout << ul.x << \" \" << ul.y << \" : \";\n","\t\tcout << w << \" \" << h << \"\\n\";\n","\t}\n","\tfriend bool bounding(Rectangle &rec, Circle &cir);\n","private:\n","\tPoint ul;\n","\tint w, h;\n","};\n","\n","void move_all(vector<Shape*>& v, Point to)\n","{\n","\tfor (auto p : v)\n","\t\tp->shift(to);\n","}\n","void rotate_all(vector<Shape*>& v, int angle)\n","{\n","\tfor (auto p : v)\n","\t\tp->rotate(angle);\n","}\n","\n","void draw_all(vector<Shape*>& v)\n","{\n","\tfor (auto p : v)\n","\t\tp->draw();\n","}\n","\n","bool bounding(Rectangle &rec, Circle &cir)\n","{\n","\treturn  (cir.c.x - cir.r)>=(rec.ul.x) && (cir.c.x+cir.r)<=(rec.ul.x+rec.w)\n","\t\t\t&& (cir.c.y - cir.r)>=(rec.ul.y) && (cir.c.y+cir.r)<=(rec.ul.y+rec.h);\n","}\n","} // namespace shapes\n","\n","int main()\n","{\n","\tusing namespace shapes;\n","\t//Shape s; // no objects of an abstract class can be created.\n","\tCircle c1 {Point{3,2},3};\n","\tCircle c2 {Point{2,5},4};\n","\tCircle c3 {Point{-2,-3},5};\n","\tRectangle r1 {Point{-3,-1},10,10};\n","\tvector<Shape*> cp {&c1, &c2, &c3, &r1};\n","\n","\tcout << \"Three circles:\\n\";\n","\tdraw_all(cp);\n","\tcout << \"Shifted by (5, 10)\\n\";\n","\tmove_all(cp, Point(5,10));\n","\tdraw_all(cp);\n","\n","\tcout.setf(ios::boolalpha);        // set format for bool\n","\tcout << bounding(r1, c1) << endl; // print true or false instead of 1 or 0\n","\tcout << bounding(r1, c2) << endl;\n","\tcout << bounding(r1, c3) << endl;\n","}\n"],"metadata":{"id":"ueZaPjLItKXw","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1668518678225,"user_tz":-480,"elapsed":263,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"d91f5034-024b-41a3-d271-01a263f4a778"},"execution_count":7,"outputs":[{"output_type":"stream","name":"stdout","text":["Writing E10_01.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++ E10_01.cpp -std=c++1z -o E10_01\n","./E10_01"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"Q2IIYAclOCxr","executionInfo":{"status":"ok","timestamp":1668518684585,"user_tz":-480,"elapsed":582,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"b003178a-2c44-4bab-eed5-39dcd872a377"},"execution_count":8,"outputs":[{"output_type":"stream","name":"stdout","text":["Three circles:\n","3 2 3\n","2 5 4\n","-2 -3 5\n","-3 -1 : 10 10\n","Shifted by (5, 10)\n","8 12 3\n","7 15 4\n","3 7 5\n","2 9 : 10 10\n","true\n","true\n","false\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":8}]},{"cell_type":"markdown","source":["## 自己定 List\n","\n","這個範例的程式碼稍微多一點，用到了 template、smart pointers、lambda functions。\n","\n","實作 List 常用的功能，例如 map、fold (reduce)、filter 等等。"],"metadata":{"id":"vDbcAirdZzO2"}},{"cell_type":"code","source":["%%writefile E10_02.cpp\n","#include <iostream>\n","#include <memory>\n","#include <cstdlib>\n","\n","using namespace std;\n","template<typename T>\n","class List {\n","private:\n","    struct Node\n","    {\n","        Node(T v, const shared_ptr<const Node> & tail) : val{v}, next{tail} {}\n","        T val;\n","        shared_ptr<const Node> next;\n","    };\n","    shared_ptr<const Node> head;\n","    explicit List (const shared_ptr<const Node> & nodes) : head{nodes} { }\n","public:\n","    List() { } //head{nullptr} done by shared_ptr\n","    List(T val, const List & tail): head{make_shared<Node>(val, tail.head)} { }\n","\n","    bool isEmpty() const { return (head == nullptr); }\n","\n","    T car() const {\n","        if (isEmpty()) exit(EXIT_FAILURE);\n","        return head->val;\n","    }\n","    List cdr() const {\n","        if (isEmpty()) exit(EXIT_FAILURE);\n","        return List(head->next);\n","    }\n","\n","    void show() const {\n","        if (isEmpty()) std::cout << \".\\n\";\n","        else {\n","            std::cout << car() << \"->\";\n","            cdr().show();\n","        }\n","    }\n","};\n","\n","template <typename T>\n","List<T> cons(T val, List<T> tail)\n","{\n","    return List<T>{val, tail};\n","}\n","template<typename S, typename T, typename F>\n","List<S> mapl(F f, List<T> lst)\n","{\n","    if (lst.isEmpty())\n","        return List<S>();\n","    else\n","        return List<S>(f(lst.car()), mapl<S>(f, lst.cdr()));\n","}\n","template<typename T, typename P>\n","List<T> filter(P p, List<T> lst)\n","{\n","    if (lst.isEmpty())\n","        return List<T>();\n","    if (p(lst.car()))\n","        return List<T>(lst.car(), filter(p, lst.cdr()));\n","    else\n","        return filter(p, lst.cdr());\n","}\n","template<typename S, typename T, typename F>\n","S foldr(F f, S accumul, List<T> lst)\n","{\n","    if (lst.isEmpty())\n","        return accumul;\n","    else\n","        return f(lst.car(), foldr(f, accumul, lst.cdr()));\n","}\n","template<typename S, typename T, typename F>\n","S foldl(F f, S accumul, List<T> lst)\n","{\n","    if (lst.isEmpty())\n","        return accumul;\n","    else\n","        return foldl(f, f(accumul, lst.car()), lst.cdr());\n","}\n","template<typename T, typename F>\n","void foreach(F f, List<T> lst)\n","{\n","    if (!lst.isEmpty()) {\n","        f(lst.car());\n","        foreach(f, lst.cdr());\n","    }\n","}\n","template<class T>\n","void print(List<T> lst)\n","{\n","    foreach([](T v)\n","    {\n","        cout << v << \"->\";\n","    }, lst);\n","    cout << \".\";\n","}\n","template<typename T>\n","List<T> concat(const List<T> a, const List<T> b)\n","{\n","    if (a.isEmpty())\n","        return b;\n","    return List<T>(a.car(), concat(a.cdr(), b));\n","}\n","template<typename T>\n","T findmax(const List<T>  a)\n","{\n","    return foldl([](T acc, T x){return (acc>x) ? acc : x;}, a.car(), a);\n","}\n","List<int> qqsort(const List<int> a)\n","{\n","\n","    if (a.isEmpty()) return a;\n","\n","    int piv = a.car();\n","    List<int> le = qqsort(filter<int>([=](int x){return piv>x;}, a.cdr()));\n","    List<int> ri = qqsort(filter<int>([=](int x){return piv<=x;}, a.cdr()));\n","    return concat<int>(le, cons(piv, ri));\n","}\n","\n","int main()\n","{\n","    List<int> l;\n","    List<int> n = cons(4, cons(5, cons(6, cons(7, cons<int>(8, l)))));\n","    l.show();\n","    n.show();\n","    auto m0 = mapl<double>([](int i){return i*0.5;} , n); // List<double>\n","    m0.show();\n","    n.show();\n","    auto m = mapl<int>([](int i){return i;} , n); // List<int>\n","    m.show();\n","    m = filter<int>([](int i){ return i%2==0;}, n);\n","    m.show();\n","    cout << foldl([](int acc, int i){return acc+i;}, 0, m) << endl;\n","    print(m); // or print<int>(m);\n","    cout << endl;\n","    List<List<int>> ll;\n","    auto mm = cons(m, cons(n, ll)); // List<List<int>>\n","    foreach([](List<int> l) { cout << \"[\"; print(l); cout << \"]\" << \"->\";}, mm);\n","    cout << endl;\n","    auto g = concat(n, m); //List<int>\n","    g.show();\n","    cout << findmax(g) << endl;\n","\n","    List<int> ns = cons(9, cons(10, cons(6, cons(5, cons(4, cons(8, cons(7, l)))))));\n","    cout << \"Before: \";\n","    ns.show();\n","    ns = qqsort(ns);\n","    cout << \"After: \";\n","    ns.show();\n","}\n"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"jbAgUj0HONZ1","executionInfo":{"status":"ok","timestamp":1668493279462,"user_tz":-480,"elapsed":293,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"f4683f2f-857d-49b7-a741-30ae85ea8e5c"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting E10_02.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++ E10_02.cpp -std=c++1z -o E10_02\n","./E10_02"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"15HoZpdK5iKH","executionInfo":{"status":"ok","timestamp":1668493285875,"user_tz":-480,"elapsed":1393,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"0151ef69-8f0b-4abe-e338-9e891f9e0f0a"},"execution_count":3,"outputs":[{"output_type":"stream","name":"stdout","text":[".\n","4->5->6->7->8->.\n","2->2.5->3->3.5->4->.\n","4->5->6->7->8->.\n","4->5->6->7->8->.\n","4->6->8->.\n","18\n","4->6->8->.\n","[4->6->8->.]->[4->5->6->7->8->.]->\n","4->5->6->7->8->4->6->8->.\n","8\n","Before: 9->10->6->5->4->8->7->.\n","After: 4->5->6->7->8->9->10->.\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":3}]},{"cell_type":"markdown","source":["延伸閱讀：C++17 fold expression\n","\n","https://baptiste-wicht.com/posts/2015/05/cpp17-fold-expressions.html\n","\n","\n","\n","延伸閱讀：關於 explicit，copy-initialization 和 direct-initialization 的說明\n","\n","http://en.cppreference.com/w/cpp/language/explicit\n","\n","\n","\n","延伸閱讀：關於 lambda function\n","\n","http://en.cppreference.com/w/cpp/language/lambda"],"metadata":{"id":"Hded9hCPVmay"}}]}