一、考試內容與筆記
1. What are the three main characteristics of Object-Oriented Programming?
- Encapsulation 封裝:Type = Data + Operation。限制使用權限(public, protected, private),有利於debug,讓錯誤限制在某一個區塊。
- Inheritance 繼承:重複使用(reuse)程式碼
- Polymorphism 多型:同名的函式與一樣的參數(同樣的signature),但有不同版本的函數,使用vitual,可以解決C中Switch問題
2. Define in C++ a pointer that points to the element a [5] [10] of the array "int a [10] [20] [30] [40] " named p.
答案:int (*p)[30][40] = &a[5][10]
int a [10] [20] [30] [40]
item |
type |
size |
a[0][0][0][0] |
int |
sizeof(int) |
a[0][0][0] |
Int [40] |
sizeof(int)*40 |
a[0][0] |
Int [30][40] |
sizeof(int)*30*40 |
a[0] |
Int [20][30][40] |
sizeof(int)*20*30*40 |
C的內建矩陣其實就是指標,其矩陣名字就是一個指標,而以上為高維矩陣各個的type與size。而a[5][10]的type為int [30][40],因此宣告int (*p)[30][40] = &a[5][10],要記得加&,因為a[5][10]是一個element,要使用取址符號取址。
高維陣列,只有一個指標,所以3維陣列,也只有一個指標,故在宣告a[5][10]時,只要宣告單一指標(*p)即可,不用宣告成雙重指標(**p)。
更多陣列與指標關係,請參考[筆記]陣列與指標|C++
3. Now, assuming that the value of p in Question 2 is z, what would be the values of p + 1 and p - 1?Why?
答案:(a) z+1200*sizeof(int), (b) z-1200*sizeof(int)
因為a[5][10]的size為sizeof(int)*30*40 = 1200*sizeof(int),要告訴array每個element的type,才能正確跳躍。單一指標的加/減,會加/減n個element,而在記憶體中會加減n*size byte,所以直接印出指標的值(address),會發現相加/減前後相差n*size byte。
*指標為儲存記憶體位址 (address)的變數
更多指標運算,請參考[筆記]陣列與指標|C++
4. Again, assuming that the value of p in Question 2 is z, what would be the values of (p + 1) - p and p - (p + 1)? Why?
答案:(a) 1, (b) -1
因為指向同一個array的指標相減,代表兩指標的距離,故回傳值不會是adress,而是距離,所以其單位是element。兩指標做運算時,一定要有一個為正(+),一個為負(-),不能直接對指標做乘(*)除(/),也不能對兩指標做相加。
更多指標運算,請參考[筆記]陣列與指標|C++
5. Define in C++ a pointer "p" to the array "int a [256] ;" so that p[1] is an alias of a [0], p[2] is an alias of a [1], and so on, all the way up so that p [256] is an alias of a [255].
答案:int *p = a-1 = &a[-1]
這樣可以實作一個index為1開始的array。
更多陣列與指標關係,請參考[筆記]陣列與指標|C++
6. In C++, which four of the operators have to be defined as a member function when overloaded. Why?
答案:=, [], (), ->
因為回傳要lvalue
- return object // 相當於回傳rvalue
- return object reference // 這邊又可細分成回傳rvalue reference或lvalue reference
lvalue與rvalue除了左右關係外:
- lvalue:有名字的,例如:變數
- rvalue:匿名的,例如:值
&& 和 || 這兩個operator如果要overloading必須小心,e1 && e2 && e3 && e4……,原本如果e1為false,判斷就會結束,但如果overloading,此性質就會消失。
<<, >> voerloading時,要宣告成friend,因為我們不能動ostream物件的東西,故只能授權ostream能存取新物件的private成員。且傳參考給operator,也回傳參考(lvalue),這樣就可以連續輸入/輸出。
更多左值右值介紹,請參考[筆記]介面與實作、運算子多載、左值右值、參數傳遞、回傳多值|C++
7. What would be the output of the following C++ program?
答案:0,4,16,36
目的:
模板超程式設計(英語:Template metaprogramming,縮寫:TMP)是一種超程式設計技術,編譯器使用模板產生暫時性的原始碼,然後再和剩下的原始碼混合並編譯。這些模板的輸出包括編譯時期常數、資料結構以及完整的函式。如此利用模板可以被想成編譯期的執行。
- template <int I = 0, int ...D> struct Helper : Helper<I+ 1, D..., (I+I)*(I+I)> {};
- template<> struct Helper<0, <> > : Helper<0 + 1, (0+0) * (0+0)> {};
- template<> struct Helper<1, <0> > : Helper<1 + 1, 0, (1+1) * (1+1)> {};
- template<> struct Helper<2, <0, 4> > : Helper<2 + 1, 0, 4, (2+2) * (2+2)> {};
- template<> struct Helper<3, <0, 4, 16> > : Helper<3 + 1, 0, 4, 16, (3+3) * (3+3)> {};
- template<> struct Helper<4, <0, 4, 16, 36> > {static constexpr std::array<int, S> table = {0, 4, 16, 36};};
細節:
- constexpr:complier time const variable
- #15, 16:是一個可變參數的遞迴模板結構helper,template<>傳入兩種參數,一種為一個int I,另一種為int ...I(可變參數),而helper自己呼叫自己,並傳三種引數給自己分別為(1)I+1, (2) D... (3) (I+I)*(I+I)。故每展開一個遞迴,參數就變多一個。
- #19~21:是一個特殊化的模板結構helper,用於終止遞迴
- … args : packed parameter
- args… : unpacked parameter
- helper<>::table:呼叫helper中的table,因為helper模板中已有預設的參數,故<>中可為空模板
8. What would be the output of the following C++ program?
#include <iostream> int main() { int a = 10; int b = 20; int z = (!!a << 3) | (!!b << 4); std::cout << z << std::endl; }
答案:24
首先要分清楚!和~這兩個差別。
- ! : logical NOT
- ~ : bitwise NOT
- | : bitwise OR
- << : shift left
- int a = 10; // 1010(2)
- int b= 20; // 10100(2)
- !a == false == 0
- !!a == true == 1
- !!a << 3 == true << 3 == 1 << 3 == 1000(2) == 8
- !!b < <4 == 10000(2) == 16
- (!!a << 3) | (!!b << 4) == 1000(2) | 10000(2) == 11000(2) == 24
9. Is the following C++ program correct? If not, show how to correct it.
template<class T> class Handle { T* p; public: Handle(T* pp) : p{pp} {} // default constructor ~Handle() { delete p; } // destructor Handle(Handle&& h) :p{h.p} { h.p=nullptr; } // move constructor Handle& operator=(Handle&& h) { delete p; p=h.p; h.p=nullptr; return *this; } // move assignment operator };
Handle(Handle&& h) :p{h.p} { h.p=nullptr; } // move constructor, 舊的object一定要接上nullptr,因為如果不接上nullptr,新舊參考都指向同一個東西,舊的object會自動呼叫destructor,則舊的object所指向的東西也會一並刪除,此時新的參考所指向的東西就會被free掉。
Handle& operator=(Handle&& h) { delete p; p=h.p; h.p=nullptr; return *this; } // move assignment operator,少檢查if(this != &h),因為要避免自我賦值。
程式碼來源:Bjarne Stroustrup. 2016. C++11 - the new ISO C++ standard
更多類別介紹,請參考[筆記]類別、特殊函式、內嵌函式、函式物件|C++
10. Implement the copy constructor and copy assignment operator for the class in Question 9 so that its instances can only be moved, but not copied.
- Handle(const Handle&) = delete; // copy constructor, delete 是指no copy
- Handle& operator=(const Handle&) = delete; // copy assignment operator, delete 是指no copy
更多類別介紹,請參考[筆記]類別、特殊函式、內嵌函式、函式物件|C++
三、相關文章
三、考試資訊
- 學期:109-2
- 課程:高等物件導向程式設計
- 學系:國立中山學資訊工程學系碩士班
- 老師:江明朝
留言
張貼留言