C++筆記
最基本的語法和撰寫注意事項,像是Operator Overloading這類比較進階而且集大成的部分可以直接看書的Ch. 11,關於Template、Exception Handling、File Processing、struct、STL等可以看課本
語法
基本
- Basic Class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# include <iostream> using namespace std; class GradeBook { public: void displayMessage() { cout << "Welcome to the Grade Book!" << endl; } }; int main() { GradeBook myGradeBook; myGradeBook.displayMessage(); } - if(Conditional Operator):
1
cout << (grade >= 60 ? "Passed" : "Failed") - For Loop
1
2for (int counter = 1; counter <= 10; counter++>) count << counter << endl; - new例子
1
2
3
4
5
6
7dataType variableName = new (class object/array/dataType(value)) Time *timePtr = new Time; delete timePtr; double *ptr = new double(3.14); int *gradeArray = new int[10]; int gradeArray[] = new int[10]; delete [] gradeArray;
Reference
和Pointer不一樣,是完全兩個不同的東西,所以&不是取位址,以下例子代表y永遠參考(綁定)x,所以改y就會改道x,因為實際的記憶體中只有一份data,y也不是一個獨立的空間。使用refernce之前要初始化
1 |
|
Array
type arrayName[ arraySize ];,代表array中所有的element都是同樣的data type,如果想要什麼type都能放,要用vector搭配Variant
1 |
|
另外,array也可以當作argument傳入function
1 |
|
多維的表示方式: int a[2][3];
vector
是一種class template,所以要使用template notation的寫法。一般來說使用vector的頻率會比array多很多,因為大部分時候不確定大小,如果大小固定並且追求極致效能,那再用array
1 |
|
Pointer
1 |
|
Pointer 搭配 Const的應用
| Pointer本身 | 被指向的對象 | |
|---|---|---|
int *Ptr; |
✅ | ✅ |
const int *Ptr; |
✅ | ❌ |
int * const Ptr = &x; |
❌ | ✅ |
const int *const Ptr = &x; |
❌ | ❌ |
Pointer和Array的關係
1 |
|
Function
ArgumentName前面可以加static/const/static const
1 |
|
Function Template
是Function Overloading的推演,既然所有logic都一樣,只有data type不同,那就設計一個邏輯通用的template,讓compiler自行推導該用什麼data type(實際使用的時候)
1 |
|
T可以帶入int, double, float, char之類的
const Member Function
1 |
|
Class
static/const/static const可以用在object,都有不同的效果,但不能用在class之前;另外,member function 和data member也都可以加static/const/static const
1 |
|
friend Keyword 範例
1 |
|
Function Lifetime
- Global Function
- Static Function in
main() - Static Function in Local
- Function in
main() - Function in Local
初始化const data member
1 |
|
Enable Cascaded Function Calls
意思就是可以讓function進行串接,達到function的return直接傳遞給下一個function當作argument input,例如: t.
setHour(18).setMinute(30).setSecond(22);
1 |
|
OOP(Object-Oriented Programming)
只要先記住,繼承就是class可以不用從頭開始撰寫,也可以直接沿用別人的class再往下開發;多型則是分成overriding(覆寫)/overloading(多載)兩種;封裝則是設定class中各個成員的存取權限,例如Public/Private/Protected等
Inheritance(繼承)
| Base-class member access specifier\Type of inheritance | public inheritance | protected inheritance | private inheritance |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | Hidden | Hidden | Hidden |
1 |
|
Polymorphism(多型)
- Overriding 是「不同 class、同函式、執行期決定」
- Overloading 是「同一 scope、同名不同參數、編譯期決定」
Overriding
Derived class 重新定義 base class 的 virtual function
1 |
|
詳解第三個例子: 在書中的例子中,print() member function是baseObject的print(),但顯示的卻是derivedClass的object data,會使用derivedClass的object data很直觀,因為目前的ptr指向derivedClass object,而data又是屬於object所以當然會印出derivedClass object的data,而使用basedClass的print member function是因為basedObjectPtr初始化的時候就是被assigned basedObject,所以compiler會直接在編譯期間就binding,除非使用virtual才會強制讓compiler在執行期間才決定使用哪一個object的print
- Virtual
為了避免compiler事先static binding,就要使用virtual這個keyword,讓compiler在執行的時候再決定要用哪一個method(dynamic binding/late binding)
1
virtual dataType memberFunctionName() const;
Pure virtual function
如果basedClass中,有一個function是很多derivedClass都必須要客製化,不能事先定義的話,那就要特別使用這個pure virtual function,也就是先定義interface,實作的部分交給各個derivedClass
1 |
|
例如課本中提到的Employee Class(Based Class)中,有earnings function,被很多derivedClass繼承之後,會衍生出其他的earning function,但計算的方式都不一樣
| Class Name | 計算方式 |
|---|---|
| Employee | = 0 |
| Salaried-Employee | weeklySalary |
| Hourly-Employee | (hours <= 40 ? (wage * hours) : ((40 * wage) + ((hours - 40) * wage * 1.5))) |
| Commission-Employee | commissionRate * grossSales |
| BasePlus-Commission-Employee | baseSalary + (commissionRate * grossSales) |
Encapsulation(封裝)
| 修飾詞 | Class內 | 子類 | Class外 |
|---|---|---|---|
| public | ✅ | ✅ | ✅ |
| protected | ✅ | ✅ | ❌ |
| private | ✅ | ❌ | ❌ |
- 如果要讓derived class能使用data member但又不想要class以外的scope能夠存取,那麼就要用protected
開發注意事項
Header 可以寫什麼
-
class/struct的宣告1
2
3
4
5
6
7
8
9// foo.h class Foo { public: Foo(); // 建構子宣告 void bar(); // member function 宣告 private: int x; }; - 常數、型別定義
1
2
3
4
5// config.h constexpr int MAX_SIZE = 100; using ID = unsigned int; typedef unsigned long ulong; - Template: 實作也要寫在header file中,和一般的class不一樣
1
2
3
4
5// max.h template<typename T> T max(T a, T b) { return a > b ? a : b; }
Header 和 CPP 要分開
- header 負責「說有什麼」,source 負責「怎麼做」,也就是前者只負責宣告 Member Variable 和Member Functions,但把實作寫在後者,
- 因為假設把兩者都寫在同一個cpp,那麼其他cpp需要用到某個function就無法使用,也不可以把實作直接寫在header file中
否則:
- 增加編譯時間
一般來說使用者會拿到
.h+ (.dllora),前者類似給使用者的說明書,讓他知道可以用什麼以及怎麼用,然後include之後實際使用的program則是會放在.dll或.a中,編譯的時候會直接link過去,好處是可以把實作的細節褒裝起來不讓其他人輕易看到,以及要修改header file的實作細節時,所有include的cpp不需要再重新編譯 - 破壞封裝(Encapsulation)
封裝的核心是:用的人只知道「能做什麼」,不知道「怎麼做到」,如果 header 暴露實作:
- 私有資料結構被看見
- 未來很難改內部實作
- 使用者可能「依賴細節」
- 降低可維護性與可讀性: 實作混進來後: Header 又長又亂、找介面變困難、新人難上手
++a VS a++
前者是先+1再往後使用,後者則是相反
1 |
|
Function Overloading
可以定義名稱相同的function,只要return/argument的 data type不同,signature就會不一樣,那compiler就會視為不同的東西
Recusive VS. Iterative Function
前者是重複動作並呼叫自己的function,後者則是利用for-loop, while-loop, do-while-loop之類的counter-controlled方式進行重複動作,兩者的terminate方式也不同