[筆記]109-2高等物件導向程式設計 期中考

一、考試內容與筆記

 1. What are the three main characteristics of Object-Oriented Programming?

  1. Encapsulation 封裝:Type = Data + Operation。限制使用權限(public, protected, private),有利於debug,讓錯誤限制在某一個區塊。
  2. Inheritance 繼承:重複使用(reuse)程式碼
  3. 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)是一種超程式設計技術,編譯器使用模板產生暫時性的原始碼,然後再和剩下的原始碼混合並編譯。這些模板的輸出包括編譯時期常數、資料結構以及完整的函式。如此利用模板可以被想成編譯期的執行。

過程:

  1. template <int I = 0, int ...D> struct Helper : Helper<I+ 1, D...,  (I+I)*(I+I)> {};
  2. template<> struct Helper<0, <> > : Helper<0 + 1, (0+0) * (0+0)> {};
  3. template<> struct Helper<1, <0> > : Helper<1 + 1, 0, (1+1) * (1+1)> {};
  4. template<> struct Helper<2, <0, 4> > : Helper<2 + 1, 0, 4(2+2) * (2+2)> {};
  5. template<> struct Helper<3, <0, 4, 16> > : Helper<3 + 1, 0, 4, 16, (3+3) * (3+3)> {};
  6. 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

首先要分清楚!和~這兩個差別。

  1. ! : logical NOT
  2. ~ : bitwise NOT
  3. | : bitwise OR
  4. << : shift left
然後運算子的先後順序為 () → ! → << → | 
  1. int a = 10; // 1010(2)
  2. int b= 20; // 10100(2)
  3. !a == false == 0
  4. !!a == true == 1
  5. !!a << 3 == true << 3 == 1 << 3 == 1000(2) == 8
  6. !!b < <4 == 10000(2) == 16
  7. (!!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

三、考試資訊

  • 學期:109-2
  • 課程:高等物件導向程式設計
  • 學系:國立中山學資訊工程學系碩士班
  • 老師:江明朝

四、參考資料

留言