# OOPS筆記 戴文凱教授 ###### tags: 作者 蕭博文 --- comment >this is comment[name=99shoes][time=Tue, Apr 13, 2021 8:22 PM][color=#4fe2c5] # Ch.3 Function Basics * IPO * INPUT-PROCESS-OUTPUT[color=#4fe2c5] UML activity diagram may help * cmath * sqrt(4.0)、pow(2.0,3.0)、fabs(-7.5)、ceil(3.2)=4.0 、floor(3.2) = 3 * Extra 求0000 to 1111 ```cpp= ///求0000-1111 int main() { for(int i=0;i<16;i++) { int tmp = i; string s = ""; for(int j = 0;j<4;j++) { s = to_string(tmp%2)+s; tmp>>=1; } cout<<s<<endl; } } ``` ###### tags: 文翔 * arguments v.s. parameter 觀念 ```cpp= int main() { double price, bill; int number; cin>>number>>price; bill = totalCost(number, price); ///this is called argument } double totalCoset(int numberParameter,double price Parameter) // this is called parameter { //不重要 } ``` * vector * vector 在宣告時會有一內部capacity 先自行建立空間,直到你超過,vector的class會double空間 ps 肉眼看不到的。 * vector 初始化方式 * vector<int> name(3); 初始化3個空間 * vector<int> v = {4,5,16,8} v.push_back(25); * vector 的印法 * (int n: vector) {cout<<n<<endl;} # Ch.4 Parameters and Overloading * call by referenece v.s. call by pointer * difference在於 pointer在Main function 將 address 當value 傳去其他function; reference 則是傳記憶體的參考值 ```cpp= void getNumbers(int* parameter1)//和tmp指向相同位置 { *parameter1 = 20; cout << parameter1 << endl;//0x00affc94{20} cout << &parameter1 << endl;//0x00affba8{0x00affc94{20}} cout << *parameter1 << endl;//20 } void showNumbers(int& parameter1) { parameter1 = 20; cout << &parameter1 << endl; // 0x00aff7c4{20} cout << parameter1 << endl; //20 } int main() { int x = 5; int y = 5; int* tmp = &x;//&x= 0x00affc94 cout << tmp << endl; // tmp = 0x00affc94{5} cout << *tmp << endl; //*tmp = 5 cout << &tmp << endl; // &tmp = 0x00affc7c{0x00affc94{5}} ///由此可知tmp和&x指向相同的位置 getNumbers(tmp); cout << &y << endl; // &y = 0x00aff7c4{5} showNumbers(y); } ``` # Ch.5 Arrays * char page[30][100]; 在使用於function時 void DisplayPage(const char p [][100]) * vector的random[i] = random.at(i) * vector二維 vector<vector<int>>v{va,vb,vc} * vector二維push v.push_back(vector<int>()); * v[0].push_back(5); --- # Ch.6 Structures and Classes * **Structures** typically all members public, No member functions * struct just has public way to save the data * **Classes** typically all data members private, inteface member functions public * class has public、procted、private way to save the variables * structure解決array賦值的方法 ```cpp= struct Fruits { int apple; int bananas; int groups; float tmp_; int total_[3]; }; int main() { Fruits A{ 3,5,6,0,2,4,1.1 }; Fruits B; cout << A.apple << " " << A.bananas << " " << A.groups << " " << A.tmp_ << endl; for (int i = 0; i < 3; i++) cout << A.total_[i] << " "; cout << endl; B = A; cout << B.apple << " " << B.bananas << " " << B.groups << " " << B.tmp_ << endl; for (int i = 0; i < 3; i++) cout << B.total_[i] << " "; cout << endl; int a[10] = { 1 }; int b[10] = { 0 }; a=b /// 會出現false } //A和B的total分別輸出2 4 1 ``` * Class 講解 ```cpp= class DayOfYear // class 為一抽象概念 { public: void input(); //public 的部分為interface 用於取private void output(); private: int month; int day; }; ``` * Accessor v.s. Mutator are both called **Helper function** * Accessor member functions, called get member functions, used **in reading data;** * Mutator member functions, allowed object to **change data** --- * Class 指標 ```cpp= class Box { public: Box(double L = 2.0, double b = 2.0, double h = 2.0) { length = L; breath = b; height = h; } double Volume() { return length * breath * height; } private: double length; double breath; double height; }; int main() { Box Box1(3.3, 1.2, 1.5);//box1 addr 0x878e8a75 Box Box2(8.5, 6.0, 2.0);//box2 addr 0x00cffd94 Box* ptrBox; ptrBox = &Box1; cout << ptrBox->Volume() << endl; cout << &ptrBox << " " << ptrBox << endl;//ptrBox 0x00cffd94 &ptrBox cout << &ptrBox << " "; &ptrBox 0x005afd9c ptrBox 0x005afda8 ptrBox = &Box2;//&Box2 0X005afda8 cout << ptrBox->Volume() << endl; } ``` # Ch.7 Constructors and Other Tools * 有Constructor就不會有default值 * **Default** should always be defined. ```cpp= class DayOfYear { public: DayOfYear(int monthValue, int dayValue);// DayOfYear();設一個default值 void input(); void output(); private: int month; int day; void testDate(); //private 也可放function } //Way1 DayOfYear::DayOfYear(int monthValue,int dayValue) { month =monthValue; day = dayValue; } //Way2 DayOfYear::DayOfYear(int monthValue,int dayValue) :month(monthValue),day(dayValue){} // body left empty //Way3 在body left 裡增加private裡的function testDate(); DayOfYear::DayOfYear(int monthValue,int dayValue) :month(monthValue),day(dayValue) { testDate(); } void DayOfYear::testDate() { ...省 } int main() { DayOfYear date1,date2; date1(7,4);//可 date2.DayOfYear(5,5);//不可呼叫自己的建構子 date3 = DayOfYear(1,3); //可 } ``` * Inline Function * Function 的執行會耗費很大的成本,用inline的話,cache會把程式搬過來,但花費很大的space,所以inline效率快占空間 * For class member functions: * Place implementation(code)for function **IN** class definition * For non-member functions: * Use keyword inlne in function declaration and function heading * 一般放在#include 的下方 * **inline** int f(int i ){return num+num} * Macro like Inline function ch獨到鍵盤中最後一個字元 * Inline用compiler作處理 macro用 preprocessor作處理 ```cpp= #include<iostream> using namespace std; #define toupper(a)((a>='a'&&((a)<='z') ? ((a)-('a' - 'A')) : (a)) int main() { char ch; printf_s("Enter a character分子:"); ch = toupper(getc(stdin))); printf_s("%c", ch); } ``` --- * Static members * all objects of class **share one copy** * One object changes it-all see changes * Can show how many objects exist at given time * 需在function外初始化 * Static functions * 裡面不能放一般的private number 或class裡的其他function,只能放static members & static functions ```cpp= #include<iostream> using namespace std; class Server { public: static int getTurn(); static int ges(); int getter(); private: static int turn; int round; }; int Server::turn = 0;//需在外面初始化靜態成員 int Server::getter() { round = 0; round++; cout << round << endl; getTurn(); turn++;//可放於function中 return turn; } int Server::getTurn() { ges();//可放靜態function //round++;//非靜態成員必須相對於特定物件 turn = 0; turn++; return turn; } int main() { Server m; cout << m.getter(); cout << m.getTurn();//靜態成員函數可被物件呼叫 // Server::getter();///非靜態成員需有相對物件 Server::getTurn(); } ``` --- # Ch.8 OperatorOverloading * Const ```cpp= const Complex Complex::operator+(const Complex& a //這裡的const 是管a裡面的member)const //後面的const是使內部data { double first_, second_; (a + 5).imaginaryValue; first_ = realValue + a.realValue; second_ = imaginaryValue + a.imaginaryValue; return Complex(-first_ + second_, second_); } ``` --- * Const* * const int*p 指到一const 等同於 int const*p * int* const p pointer指標本身是const = * const int * const p ointer都不能改 ```cpp= int main() { ///Normal 版 int a = 5; int d = 5; int* p = &a; const int* b = &a; // 不能變動指到的位置的值,但不一定要指到a的位置 a = 4; cout << &p << " " << *p; *p = 6; *b = 6;//不能改變 b=&d; int* const f = &a;//可以變動指到位置的值,但不能變動指到的位置 *f = 8; f = &d;//不能改變 const int* const g = b;//啥都不能改 } ``` --- * Operator () 、= 、[] must be overloaded as member function *Friend function* is nto a member function but it can access private members *ostream istream must be friend function ```cpp= ostream& operator<<(ostream& outputStream, const Complex& a) { outputStream << a.realValue << " + " << a.imaginaryValue << "*" << "i" << endl; return outputStream; istream& operator>>(istream& inputStream, Complex&a//不能const) { string str; getline(inputStream, str); int x = str.find('='); str.erase(str.begin(), str.begin() + x + 1); char* copyStr; const char* constc = nullptr; constc = str.c_str(); double first_ = strtod(constc, &copyStr); copyStr += 2; double second_ = strtod(copyStr, NULL); a.realValue = first_; a.imaginaryValue = second_; return(inputStream); } ``` * Prefix & Postfix ```cpp= Prefix ++X has reference 須回傳一個物件也可以不加& , 回傳value PrimeNumber& PrimeNumber:: operator++() { PrimeNumber os; os.value = value; if (os.value == 1) { os.value = 2; value = 2; return os; } int copy_value = value + 1; bool isPrime = true; for (; copy_value > 2; copy_value++) { for (int i = 2; i <= copy_value / 2; i++) if (copy_value % i == 0) { isPrime = false; break; } if (isPrime) { value = copy_value; os.value = copy_value; return os; } isPrime = true; } } Postfix X-- //回傳value PrimeNumber PrimeNumber:: operator--(int) { int transfer_Value = value; if (value == 1) return value; if (value == 2) { value = 1; return transfer_Value; } if (value == 3) { value = 2; return transfer_Value; } int copy_value = value - 1; bool isPrime = true; for (; copy_value > 2; copy_value--) { for (int i = 2; i <= copy_value / 2; i++) if (copy_value % i == 0) { isPrime = false; break; } if (isPrime) { value = copy_value; return transfer_Value; } isPrime = true; } } ``` --- * Rvalue 等號右邊 Lvalue等號左邊,要有一個位置 --- # Ch.9 String ```cpp= int n; string line; cin>>n; cin.get();//this can solve the problem below getline(cin,line); // if input is:42 &Hello hitchhiker , n set to 42,but line set to empty string!, 因為"\n" 停留在gteline()裡 ``` # 題目練習 Fraction Numerator Denominator ```cpp= void Fraction::getDouble()////化成小數形式輸出 { double temp1 = ((double)numerator / (double)denominator); int temp2 = numerator / denominator; if (temp1 == temp2)///確認是否為整數 { cout << temp1 << endl; } else cout << fixed << setprecision(6) << temp1 << endl;///取小數後六位 cout.unsetf(ios::fixed); } void Fraction::outputReducedFraction()///化成分數形式輸出 { int temp1 = numerator; int temp2 = denominator; if ((temp1 % temp2) == 0)/////如果為整數 { cout << temp1 / temp2 << endl; } else {///////////取最小分數 while (temp1 != 0 && temp2 != 0) { if (temp1 >= temp2) temp1 = temp1 % temp2; else temp2 = temp2 % temp1; } if (temp1 > 0) { numerator /= temp1; denominator /= temp1; } else { numerator /= temp2; denominator /= temp2; } cout << numerator << "/" << denominator << endl; } } ``` --- * 輾轉相除法 ```cpp= int GCD(int input_1, int input_2) { if (input_2 == 0) return input_1; return GCD(input_2, input_1 % input_2); } ``` --- * 九宮格算法 ```cpp= #include<iostream> using namespace std; #include<sstream> #include<vector> int main() { stringstream input_; string input_1; int** p = new int* [9]; for (int i = 0; i < 9; i++) { p[i] = new int[9]; } while (true) { int i = 0; while (getline(cin, input_1) && i < 9) { int k = 0; for (int j = 0; j < input_1.size(); j++) if (input_1[j] <= '9' && input_1[j] >= '0') { input_ << input_1[j]; input_ >> p[i][k]; k++; input_.str(""); input_.clear(); } i++; } if (i != 9) break; ////determine //for (int X = 0; X < 3; ++X) { // for (int Y = 0; Y < 3; ++Y) { // for (int x = 0; x < 3; ++x) { // for (int y = 0; y < 3; ++y) { // p[X * 3 + x][Y * 3 + y] = 0; // } // } // } //} //i % 3 = X; //i / 3 = Y bool de[9] = { false }; bool decision = true; for (int i = 0; i < 9; ++i) { for (int j = 0; j < 9; ++j) { de[p[(i % 3) * 3 + j % 3][(i / 3) * 3 + j / 3] - 1] = true; } for (int k = 0; k < 9; ++k) if (de[k] == false) { cout << "False" << endl; decision = false; break; } } bool de3[9] = { false }; if (!decision)continue; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) de3[p[i][j] - 1] = true; for (int k = 0; k < 9; ++k) if (de3[k] == false) { cout << "False" << endl; decision = false; break; } } bool de2[9] = { false }; if (!decision)continue; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) de2[p[j][i] - 1] = true; for (int k = 0; k < 9; ++k) if (de2[k] == false) { cout << "False" << endl; decision = false; break; } } cout << "True" << endl; } } ``` * 檔案輸出入教學 ```cpp= #include<iostream> #include<fstream> using namespace std; #include<vector> void arrangement(vector<int>& a, vector<int>& b)////將a輸入並排列,算好每個值的個數並放入b裡面 { /////////bubble sort int length_ = a.size(); while (length_ > 1) { length_--; for (int i = 0; i < length_; i++) { // 如果前面的元素比後面的元素要大,則交換元素位置 if (a[i] > a[i + 1]) { int tempValue = a[i]; a[i] = a[i + 1]; a[i + 1] = tempValue; } } } int count_ = 1; /////////將值和值的個數分別push進b陣列裡 for (int i = 0; i < a.size() - 1; i++) { if (a[i] == a[i + 1]) count_++; else { b.push_back(a[i]); b.push_back(count_); count_ = 1; } } /////如果算到最後都一樣 if (a[a.size() - 1] == a[a.size() - 2]) { b.push_back(a[a.size() - 1]); b.push_back(count_); } if (a[a.size() - 1] != a[a.size() - 2]) { b.push_back(a[a.size() - 1]); b.push_back(count_); } } int main() { //////讀檔 ifstream fin("grade.txt"); if (!fin) { cout << "檔案無法開啟\n"; return 1; } vector<int>box_; vector<int>boxTemp_; int input_; while (fin >> input_) { box_.push_back(input_); } ///讀檔結束 fin.close(); arrangement(box_, boxTemp_); /////寫檔 ofstream fout("grades.Output"); int c[6] = { 0,1,2,3,4,5 }; int count_2 = 1; for (int i = 0; i < 6; i++) { if (c[i] != boxTemp_[count_2 - 1]) fout << "0 grade(s) of " << i << endl; else { fout << boxTemp_[count_2] << " grade(s) of " << boxTemp_[count_2 - 1] << endl; count_2 += 2; } } fout.close(); //寫檔結束 } ``` --- # Strfind ```cpp= #include<iostream> #include<string> using namespace std; int main() { string str("Please, replace the vowels in this sentence by asterisks."); size_t found = str.find_first_of("aeiou", 6); while (found != string::npos) { cout << found << str[found] << endl; str[found] = '*'; found = str.find_first_of("aeiou", found + 1); } cout << str << endl; } ``` --- # 檔案輸出入進階 ```cpp= #include<iostream> #include<fstream> using namespace std; #include<string> #include<sstream> int main() { string input_; cin >> input_; ifstream fin(input_); stringstream ss; if (!fin) cout << "can't open"; else { while (getline(fin, input_)) { int first; string second; double third; ss << input_; cout << ss.str() << endl; ss.str("1\n2\n3\n4\n5\n"); cout << ss.str(); ss >> first >> second >> third; cout << first << " " << second << " " << third << endl; string fourth; fourth = to_string(first); fourth.empty() ? cout << "empty\n" : cout << fourth << endl; second += "4"; cout << second << endl; ss.str(""); ss.clear(); } } fin.close(); } ``` # 神奇演算法 海岸線 ```cpp= #include <iostream> #include<vector> using namespace std; class point { public: int x, y; point() { x = 0; y = 0; } point(int x_, int y_) { x = x_; y = y_; } }; class Node { public: point p; Node* next; Node() { p.x = 0; p.y = 0; next = NULL; } Node(point p_) { p.x = p_.x; p.y = p_.y; next = NULL; } }; bool smaller(int a1, int c1, int a2, int c2) { return a1 < a2 || (a1 == a2 && c1 < c2); } void Sort(vector<int>& area, vector<int>& coast) { for (int i = 0; i < area.size() - 1; ++i) { for (int j = 1; j < area.size() - i; ++j) { if (smaller(area[j - 1], coast[j - 1], area[j], coast[j])) { swap(area[j - 1], area[j]); swap(coast[j - 1], coast[j]); } } } } int main() { int w, h; cin >> h >> w; bool** map, ** map2; map = new bool* [w + 2]; map2 = new bool* [w + 2]; for (int i = 0; i < w + 2; ++i) { map[i] = new bool[h + 2]{ 0 }; map2[i] = new bool[h + 2]{ 0 }; } for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { char c; cin >> c; map[x + 1][y + 1] = (c == '#'); map2[x + 1][y + 1] = map[x + 1][y + 1]; } } vector<int> Areas, Coasts; int mx[4]{ 0,0,-1,1 }, my[4]{ -1,1,0,0 }; for (int y = 1; y < h + 1; ++y) { for (int x = 1; x < w + 1; ++x) { if (map2[x][y]) { //island Node* head = new Node(point(x, y)), * rear = head; Node* flag = head; map2[flag->p.x][flag->p.y] = 0; while (flag != NULL) { for (int i = 0; i < 4; ++i) { if (map2[flag->p.x + mx[i]][flag->p.y + my[i]]) { Node* newnode = new Node(point(flag->p.x + mx[i], flag->p.y + my[i])); map2[flag->p.x + mx[i]][flag->p.y + my[i]] = 0; rear->next = newnode; rear = rear->next; } } flag = flag->next; } for (int y = 1; y < h + 1; ++y) { for (int x = 1; x < w + 1; ++x) { cout << map2[x][y]; } cout << endl; } int area = 0, coast = 0; while (head != NULL) { area++; for (int i = 0; i < 4; ++i) { if (map[head->p.x + mx[i]][head->p.y + my[i]]) { coast--; } } Node* tmp = head; head = head->next; delete tmp; } coast += (area << 2); Areas.push_back(area); Coasts.push_back(coast); } } } //sorting Sort(Areas, Coasts); for (int i = 0; i < Areas.size(); ++i) { cout << Areas[i] << " " << Coasts[i] << endl; } } ``` # 海岸線地回版 ```cpp= #include<iostream> using namespace std; #include<vector> #include<cmath> int main() { int w, h; int total = 0; vector<int> resultX, vector<int> resultY; for (int i = 0; i < resultX.size(); ++i) { for (int dir = 0; dir < 4; ++dir) { total += 4; if (map[resultX[i] + mx[dir]][resultY[i] + my[dir]] == 1) total--; } } } int mx[4]{ 0,0,-1,1 }, my[4]{ -1,1,0,0 }; void Search(vector<int>& resultX, vector<int>& resultY, bool** map, int w, int h, int x, int y) { map[x][y] = 0; resultX.push_back(x); resultY.push_back(y); for (int i = 0; i < 4; ++i) if (map[x + mx[i]][y + my[i]] == 1) Search(resultX, resultY, map, w, h, x + mx[i], y + my[i]);//up if (map[x][y - 1] == 1) Search(resultX, resultY, map, w, h, x, y - 1);//up i==0 if (map[x][y + 1] == 1) Search(resultX, resultY, map, w, h, x, y + 1);//up if (map[x + 1][y] == 1) Search(resultX, resultY, map, w, h, x + 1, y);//up if (map[x - 1][y] == 1) Search(resultX, resultY, map, w, h, x - 1, y);//up } ``` # NumberGame ```cpp= #include"NumberGame.h" void NumberGame::SetInput(int input)// : set the given integer A. { input_ = input; } void NumberGame::ProcessInput()// : splitting the integer A into several digits. { int a; while (input_ > 0) { a = input_ % 10; /* if (a == 5) factor[0]++; else if (a == 7) factor[1]++; else*/ processInput_.push_back(a); input_ /= 10; } } void NumberGame::SetFileName(string input_)//: set the file name of the file where list S is located. { fileInput_ = input_; } void NumberGame::LoadNumberList()// : read list S from the file. { int a; ifstream fin(fileInput_); if (!fin) cout << "檔案無法開啟" << endl; else { while (!fin.eof()) { fin >> a; listS.push_back(a); } fin.close(); } } void NumberGame::PrintAllValid() //: print all the valid numbers in S ascendingly { //vector<int>corresponded;///放入符合的資料 sort(processInput_.begin(), processInput_.end()); bool whether_0 = false; while (processInput_[0] == 0)//將0刪除 { whether_0 = true; processInput_.erase(processInput_.begin()); } bool divide = false; bool pass_ = false; bool whether_1 = false;//用來判斷是否有1 vector<int>repeat;//儲存重複index vector<int>corresponeded;//儲存符合的資料 while (processInput_.size() > 0 && processInput_[0] == 1) { whether_1 = true; processInput_.erase(processInput_.begin()); } ///////////////////////////////////// bool retmp = false; int tmp = 0; int count_ = 0; int cotmp = processInput_.size(); //point 因為processinput_.size()==0時會進入以下的for迴圈,所以用cotmp來代替 for (int i = 0; i < cotmp - 1; i++)//用來記錄ProcessInput裡是否有重複的 { int j = i; while (j != processInput_.size() - 1 && processInput_[j] == processInput_[j++])//儲存數字 //重複的個數 { tmp = processInput_[j]; count_++; retmp = true; } if (processInput_.size() - 1 >= j && tmp == processInput_[j - 1]) count_++; if (retmp) { repeat.push_back(tmp);//儲存重複的數字 repeat.push_back(count_);///重複個數 retmp = false; i += count_ - 1; count_ = 0; } } for (int i = 0; i < listS.size(); ++i) { int val = listS[i]; if (whether_1 && val == 1) ///判斷List裡是否有1或0 { corresponeded.push_back(val); continue; } if (whether_0 && val == 0) { corresponeded.push_back(val); continue; } if (val % 2 != 0 && val % 3 != 0 && val % 7 != 0 && val % 5 != 0)//代表是其他質數 continue; for (int k = cotmp - 1; k > cotmp / 2; k--)//做n*n/2次迴圈 { int tmp = val; for (int m = k; m >= 0; m--) { if (tmp % processInput_[m] == 0) { tmp /= processInput_[m]; divide = true; } else//來確定這個數字是否有重複的可能性,節省之後跑回圈的次數 { divide = false; if (repeat.size() > 0) { for (int k = 0; k < repeat.size(); k += 2) if (processInput_[m] == repeat[k]) { continue; m += repeat[k + 1]; } } } if (tmp == 1 && divide)//如果tmp是1且divide成立就輸出 { corresponeded.push_back(listS[i]); pass_ = true; break; } } if (pass_) { pass_ = false; break; } } } sort(corresponeded.begin(), corresponeded.end()); for (int i = 0; i < corresponeded.size(); i++) cout << corresponeded[i] << endl; } void NumberGame::Reset() ///: reset all variables. { listS.clear(); processInput_.clear(); } ``` # Ch11 Separate complication and namespaces #### Encapsulation rules - 成員變數為private,由成員函數(public)存取 #### Interface in header file 定義,Implementation in .cpp file 實作 #### NameSpace ![](https://i.imgur.com/DQKBgJv.png) - main function 含多個namespace時要用block區分 ####unNameNamespace只能用於internal linkage(同屬一個.cpp) e.g. 像是我定義一個nameSpace latTop , latTop裡分別有user and passWord 而且 user and passWord裡面分別有一個invalid()做判斷,這時要用unNameNamespace去寫Invalid()。ps: user and password分別在不同.cpp unnameNamespace裏頭定義的variable像是全域變數,但只能給特定的.cpp使用 ![](https://i.imgur.com/JkAkXrR.png) #### 如果沒有第16行,void h()裡面讀不到j,如果有16行則void h()裡面的i無法辨別,所以可將j指定A::j解決問題。 # Ch12 Streams and File I/O ## Streams在此強調不只是螢幕輸入,來源可能有很多種,以下則是我們目前學到的 ##### Input stream - from file or keyboard ##### Output stream go to screen or file ``` cpp= #include<fstream> using namespace std; ifstream inStream; ofstream outStream; inStream.open("infile.txt"); int oneNumber,anotherNumber; inStream>>oneNumber>>anotherNumber; outStream.open("outfile.txt"); outStream<<"oneNumber="<<oneNumber<<"anotherNumber="<<anotherNumber; ``` #### Flush 將暫存在buffer的輸入寫入檔案 ```cpp= #include <ostream> // std::flush #include <fstream> // std::ofstream int main() { std::ofstream outfile("test.txt"); for (int n = 0; n < 100; n++) outfile << n << std::flush; outfile.close(); return 0; } ``` #### Check whether file is fail ```cpp= inStream.open("stuff.txt"); if(inStream.fail()) { cout<<XXXX\n; exit(1); } ``` #### Check End of file 只能get char 型態 ,輸入atoi,輸出a i ```cpp= int main() { ifstream inStream; char next; inStream.open("stuff.txt"); inStream.get(next); //GET a char op; while (!inStream.eof())//單純只是讀並沒有inputt { cout << next;//如果沒有以下兩行則一直讀到a inStream >> op;//t//有Input inStream.get(next);//o//有input } 使用while(!instream.eof()) { 不管是inStream>>next 或是inStream.get(next) 輸出皆會是atoii } 但如果是以while(inStream>>next) 或是while(inStream.get(next)) 會輸出atoi 所以.eof有buffer的問題 } ``` #### Formatting cout.width(5)=cout<<setw(5)都只能影響下一個輸出 cout.precision(5)=cout<<setPrecision(5)//設定輸出個數,接只能影響下一個 cout.setf(ios::fixed)= setiosflags(ios::fixed);//設定小數個數 ```cpp= double s = 20.7843909 /*cout<<setprecision(2)<<s<<endl;//输出21 cout<<fixed<<s<<endl;//输出20.78*/ /*cout<<setprecision(2)<<s<<endl;//输出21 cout<<showpoint<<s<<endl;//输出21.(有个点)*/ /* cout<<fixed<<s<<endl;//输出20.784391 cout<<showpoint<<s<<endl;//输出20.784391*/ /*cout<<setprecision(2)<<s<<endl;//输出21 cout<<showpoint<<s<<endl;//21.(有个点) cout<<fixed<<s<<endl;//20.78*/ ``` #### Saving Flag settings 在此判斷OutStream會將上次的回傳位置傳給這次的所以判斷是延遲,但輸出正常 在此如果將第20行拿掉 會輸出0 30 60 90 將第21行拿掉0.000000 30.141593 60.283185 90.424778 ``` cpp= #include <ostream> // std::flush #include <fstream> // std::ofstream #include<istream> #include<iostream> #include<iomanip> #include<vector> const double PI = 30.141592653; using namespace std; void outputStuff(ofstream& outStream) { int precisionSetting = outStream.precision(); // = 6 long flagSettings = outStream.flags();// // flagSettings = 513 outStream.setf(ios::fixed | ios::showpoint); int a = outStream.precision(3);//a=6 for (int n = 0; n < 4; n++) outStream << PI * n << std::flush << endl; a = outStream.precision(2);//a=3 for (int n = 0; n < 4; n++) outStream << PI * n << std::flush << endl; int b = outStream.precision(precisionSetting);//b =2 int c = outStream.flags(flagSettings);//c= 8721 for (int n = 0; n < 4; n++) outStream << PI * n << std::flush << endl; cout << setprecision(2) << PI; } ``` ![](https://i.imgur.com/wVGvOv5.png) stringstream教學 ![](https://i.imgur.com/oGRfRyD.png) ``` cpp= #include<iostream> #include<sstream> int main() { string b = "holy Bible\n"; istringstream in(b); string word1, word2, word3, word4; in >> word1; in.seekg(3);//去指定字串位置找字串,空白停止 e.g.in.seekg(3) 輸出y in.seek(6)ible in >> word2; cout << word1 << " " << word2 << endl; // //word1 = holy word2 = y in >> word3; cout << word3 << " ";word3 = Bible // 如果是seekg(5)則會變成 word2 = Bible word3 = "" in >> word4; cout << word4 << " ";word4 = "" } ``` # Chap13 Recursion ### Point - 不要寫成無限遞迴 -終止條件須回傳正確值 -遞迴須回傳正確值 -確認大問題能拆解成相同的小問題 ### 確認是否為prime ```cpp= bool isPrime(int p,int i =2) { if(i==p)return 1; if(p%i==0) return 0; return isPrime(p,i+1); } ``` ### 確認是否為GCD最大公因數 在此m>n ```cpp= int GCD(int m, int n) { if ((m % n) == 0)return n; return GCD(n, m % n); } ``` ### 認是基數個1還是偶數個 ```cpp= bool oddNumberOfOnes(string s); bool evenNumberOfOnes(string s) { if (s.length() == 0) return true; else if (s[0] == '1') return oddNumberOfOnes(s.substr(1)); else return evenNumberOfOnes(s.substr(1)); } bool oddNumberOfOnes(string s) { if (s.length() == 0)return false; else if (s[0] == '1')return evenNumberOfOnes(s.substr(1)); else return oddNumberOfOnes(s.substr(1)); } ``` ### Tail Recursion -more efficient -差異在於有沒有將回傳值用一個變數做儲存 not tail ![](https://i.imgur.com/xod4U6C.png) tail ![](https://i.imgur.com/Ov9nwVb.png) # Chap 14 Inheritance #### 兒子繼承父親只需定義自己的FUNCTION,其他的FUNCTION用public繼承父親的,要寫父親的get 或setfunction去拿private資料 -Parent clss refer to base class -Child class refer to derived class -一個class可繼承多個class,但不能父子互相繼承 ## FUNCTION SIGNATURE int Divide(int n, int m); double Divide(int n, int m); Constructor 和default Constructor不能繼承 只能以下面的方式 在此的CreatureDemoPinky會先呼叫CreatureDemo再呼叫Creature ```cpp= #include<iostream> using namespace std; class Creature { public: Creature(); Creature(int newType, int newStrength, int newHIt); private: int newType; int newStrength; int newHIt; }; Creature::Creature() :newType(0), newStrength(0), newHIt(0) {} Creature::Creature(int newType, int newStrength, int newHit) : newType(newType), newStrength(newStrength), newHIt(newHit) {} class CreatureDemon :public Creature { private: int height; public: CreatureDemon() :Creature(), height(0) {} CreatureDemon(int newType, int newstrength, int hit, int height) :Creature(newType, newstrength, hit), height(height) {} }; class CreatureDemonPinky :public CreatureDemon { private: int Criticalstrike; public: CreatureDemonPinky() :CreatureDemon(), Criticalstrike(0) {} CreatureDemonPinky(int newType, int newstrength, int hit, int height, int Criti) :CreatureDemon(newType, newstrength, hit, height), Criticalstrike(Criti) {} }; int main() { return 0; } ``` #### IS a v.s. Has a relationships -Inhertiance 敞篷車 is a 汽車 -Onc class has another class member data #### Default compiler provide three defaults: -Default(parameterless)Constructor -Copy Constructor -Assignment operator # Chap 15 Polymorphism and Virtual Functions ## Late Biding(Dynamic binding) 、Virtual functions ### Meaning #### Early binding 的 early 指的就是編譯的這個時間點(因為相較於執行發生較早)發生的binding,late 指的就是 run time 時發生的 binding。一般而言在編譯過程中 compiler 會去查找函數定義來進行鏈結,因此基本上預設所有 function call 都是透過 early binding(static binding)完成的。 #### virtual function 就是在 class member function 宣告前加上關鍵字 "virtual" 告訴編譯器這個 function 之後會被 overridden 所以要採用 "late binding",而 virtual function 可以實現讓同一個 function 根據不同種類的 object 而有不同的行為(函數定義),因此可以視為一種多型(Polymorphism)的方式。 1. 一個 class 中的 virtual function 在所有繼承它的子類別中自動預設此 function 為 virtual。 2. 一個沒有函數定義的 virtual function 稱做 "pure virtual function",ex: virtual void height() = 0; 3. 包含至少一個 pure virtual function 的 class 稱為 "Abstract class",Abstract class 是不能生成 object 的,只能拿來當作父類別被繼承。 4. 繼承 Abstract class 的子類別必須 override pure virtual function,否則也會變成一個 Abstract class。 預設中所有的 function call 都是採用 "early binding" 的方式進行鏈結,顯然我們必須要有某個語法來告訴編譯器先不要做binding,再拖一下,這個keyword就是 "virtual" 拉! ```cpp = using namespace std; #include <iostream> using namespace std; class Homo { public: virtual void height() { cout << "Homo height is unlimited" << endl; } }; class neanderthalensis : public Homo { public: void height() { cout << "neanderthalensis is about 1.5 meters tall" << endl; } }; int main() { Homo* h; neanderthalensis n; h = &n; // early binding h->height(); return 0; } ``` #### Overrdidden v.s. redefined Virtual funciton definition changed in a derived class is called overridden Non-virtual functions changed are called redefined 另外使用virtual functions 會耗費較大的記憶體且執行速度較慢(late binding) ### Example of abstract class ```cpp= class Base { public: virtual void show()=0; //pure virtual funciton }; class Derived:public Base { public: void show() { cout<<"Implementation of Virtual function in derived class"; } }; ``` #### Object slicing Happens when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off to form the base class object. ```cpp= class BaseCls { private: string name; public: BaseCls(const string& s) :name(s) {} virtual void show()const { cout << "Base: " << name << "Show()" << endl; } }; class DerivedCls :public BaseCls { private: string name; string habitat; public: DerivedCls(const string& sp, const string& s, const string& h) :BaseCls(sp), name(s), habitat(h) {}; virtual void show()const { cout << "DerivedCls:" << name << "Show()in" << habitat << endl; } }; void Fun1(BaseCls a) { a.show(); } void Fun(const BaseCls& a) { a.show(); } int main() { BaseCls ocBase("Base"); DerivedCls ocDerived("Test", "TEST1", "test1&test2"); cout << "pass-by-value" << endl; Fun1(ocBase); Fun1(ocDerived); // 在此的derived 傳給BaseCls a的時候會被蓋掉,變成BaseCls cout << "pass by reference" << endl; Fun(ocBase); Fun(ocDerived);//用reference則不會 return 0; } ``` #### Pure virtual destructor要實作,不像一般的pure virtual 執行順序是先呼叫自己的再呼叫祖先的 ```cpp= class BaseCls { private: public: virtual~BaseCls() = 0; virtual void show()const { cout << "Base: " << "Show()" << endl; } }; BaseCls::~BaseCls() { cout << "hi" << endl; } class DerivedCls :public BaseCls { private: int* m_pnArry; public: virtual ~DerivedCls() { cout << "Derived\n"; delete[]m_pnArry; } DerivedCls(int nLength) { m_pnArry = new int[nLength]; } }; int main() { DerivedCls* pDerived = new DerivedCls(5); BaseCls* pBase = pDerived; delete pBase; return 0; } ``` # Ch16 templates #### First line called"template prefix", tells complier what's coming is "template" and that T is a type parameter #### 如果有寫到pointer , destructor必須要寫好 ```cpp= template<class T> void swapValues(T& var1, T& var2) { T temp; temp = var1; var1 = var2; var2 = temp; } ``` #### 如果要傳入兩個不同型態引述需要兩個class T ```cpp= template<class T, class T2> void swapValues(T& var1, T2& var2) { T temp; temp = var1; var1 = var2; var2 = temp; } int main() { int a = 5; double b = 5.5; swapValues(a, b); cout << b << " " << a; } ``` #### Class Template ![](https://i.imgur.com/iidjvSj.png) ![](https://i.imgur.com/hHHTZzc.png) ![](https://i.imgur.com/Qh08T9Q.png) #### Non-template parameter ```cpp= template<int N>struct S { int a[N]; }; //*pf pointer to function // (S<10>::*a)[10] pointer to member object(of type int[10]) template<char c, int(&ra)[5], int(*pf)(int), int(S<10>::* a)[10] >struct Complicated { void foo(char base) { ra[4] = pf(c - base); } }; int a[5]; int f(int n) { return n; } int main() { S<10>s; s.a[9] = 4; Complicated<'2', a, f, &S<10>::a>c;//int (&S<10>::*)[10]長這樣 c.foo('0'); cout << s.a[9] << a[4] << endl; } ``` ## 很酷的寫法 for_each為template底下的 ```cpp= template<class InputIt, class unaryfunction> unaryfunction for_each(InputIt first, InputIt last, unaryfunction f) { for (; first != last; ++first)f(*first); return f; } int main() { vector<int>nums{ 3,4,2,8,15,267 }; auto print = [](const int& n) { cout << " " << n; }; cout << "before\n"; for_each(nums.begin(), nums.end(), print); cout << '\n'; for_each(nums.begin(), nums.end(), [](int& n) {n++; }); for_each(nums.begin(), nums.end(), print); } ``` # Ch18 Exception Handling #### Try-Throw-Catch #### Exceptions must be "handle" in some catch block ![](https://i.imgur.com/kaCYUiX.png) ## 可以重複執行的CODE 在執行Quotient的時候發現分母為0,先去class裡面將錯誤訊息放入,再跑回呼叫他的function,接下來執行main裡面的catch並輸出,接者依然能重複執行 ```cpp= #include <iostream> using std::cout; using std::cin; using std::endl; #include <exception> using std::exception; // 定義一個例外類別:DivideByZeroException // 當發生除0錯誤時可丟出此類例外 class DivideByZeroException : public exception { public: // 建構子:直接實作,指定錯誤訊息 DivideByZeroException() : exception("attempted to divide by zero") {} }; double quotient(int numerator, int denominator) { // 假如除數為0丟出 DivideByZeroException 例外並結束此函式 if (denominator == 0) throw DivideByZeroException(); //丟出例外並結束函式執行// // 傳回除法運算結果 return static_cast<double>(numerator) / denominator; } // end function quo int main() { int number1; // 使用者指定的被除數 int number2; // 使用者指定的除數 double result; // 除法運算結果 cout << "Enter two integers (end-of-file to end): "; while (cin >> number1 >> number2) { // try區塊內含可能傳回例外的程式碼 // 以及當例外發生時不應執行的程式碼 try { result = quotient(number1, number2); cout << "The quotient is: " << result << endl; } // end try // 例外處理程式:處理除0例外 catch (DivideByZeroException& divideByZeroException) { cout << "Exception occurred: " << divideByZeroException.what() << endl; } // end catch cout << "\nEnter two integers (end-of-file to end): "; } // end while cout << endl; return 0; // 正常結束 } ``` ## 函式裡面放try throw catch 先執行main裡的try在執行function throwException 接者try throw catch 在function 最後的throw 則由main裡的 catch接到 ```cpp= #include <iostream> using std::cout; using std::endl; #include <exception> using namespace std;//using std::exception; // throw, catch and rethrow exception void throwException() { // 丟出例外並利用catch捉住例外 try { cout << " Function throwException throws an exception\n"; throw exception(); // 產生例外 } // end try // 處理例外 catch (exception& caughtException) { cout << " Exception handled in function throwException" << "\n Function throwException rethrows exception"; throw; // 重新丟出例外 } // end catch cout << "This also should not print\n"; } // end function throwException int main() { // 丟出例外 try { cout << "\nmain invokes function throwException\n"; throwException(); cout << "This should not print\n"; } // end try // 處理例外 catch (exception& caughtException) { cout << "\n\nException handled in main\n"; } // end catch cout << "Program control continues after catch in main\n"; return 0; } // end main ``` # Ch19 Design Pattern ## Singleton MVC #### Data(model)- student-acting as a model #### interface(view)- studentview-print student details on console #### operation(controller)- studentcontroller(做邏輯運算CRUD)- responsible to stroe data in student object and update view studentview accordingly ## sequence diagram 個模組間的操作順序,通常只整個系統 e.g. Online shop interface->Item list-> purchase interface ## Activity diagram e.g.要了解使用者的需求,通常只使用者流程 ## 流程圖->某一個function或程式碼的流程 ## 先從activity diagram ->sequence diagram -> flow chart ## 流程圖工具 googl draw.io、 microsoft project、visual paradiam has a-> composition 你泥中有我我泥中有你