1,構造、析構與異常
對于構造函數而言:
- 不建議在構造函數中跑出異常;
- 構造函數抛出異常時,析構函數将不會執行,需要手動去釋放記憶體。
對于析構函數而言:
- 析構函數不應該抛出異常;
- 當析構函數中會有一些可能發生異常時,那麼就必須要把這種可能發生的異常完全封裝在析構函數内部,決不能讓它抛出函數之外;
- 析構函數異常相對要複雜一些,存在一種沖突狀态,程式将直接崩潰:異常的被稱為“棧展開(stack unwinding)”的過程中時,從析構函數抛出異常,C++運作時系統會處于無法決斷的境遇,是以C++語言擔保,當處于這一點時,會調用 terminate()來殺死程序。是以,當處理另一個異常的過程中時,不要從析構函數抛出異常, 抛出異常時,其子對象将被逆序析構。
2,指針與數組
Q:
main()
{
char*a[]={"work","at","alibaba"};
char**pa=a;
pa++;
printf("%s",*pa);
}
上述程式的執行結果是?
A:
首先,對于編譯器而言,是沒有數組這一概念的,數組全部都被看做指針, 是以,a[]就是*a,那麼a換成了pa,pa即是a,隻是一個名字的變化而已。根據pa++,也就是取a[1][]的值,也就是"at"
3,scanf與printf
scanf和printf對資料長度的控制不同:
- scanf不能控制精度隻能控制長度,比如%m.nf是不允許的的,但是可以指定%mf,其中m為整數。
- printf可以控制長度也可以控制精度。
4,二維數組的定義
定義二維數組,行數可以省略,但是列數一定需要指定,因為編譯器會根據列數來進行尋址。
多元數組也是一樣,隻有最靠近數組名的那一維大小可以省略。
5,類的隐式轉換
- 當A是基類,B是派生類,則此時B可以隐式轉換為A,因為向上級類型轉換時隐式的,部分元素丢棄可以自動完成。但是,A不能隐式地轉換為B,因為向下是顯式的,不知道添加的值什麼。
6,switch
switch語句中,如果不加break,則成功判斷成功之後的語句會忽略之後的case條件判斷,一直執行下去,直到break語句或者case語句。
換句話說,switch語句中沒有break會執行滿足條件的和之後的所有條件。
7,虛函數與内聯
虛函數不可以内聯,因為虛函數是在運作期間的時候确定調用的函數,而内聯函數是在編譯期間進行代碼展開,兩者沖突,是以沒有一起使用的做法。
當然,内聯隻是對編譯器的一種請求,是否真正内聯是要看編譯器的處理,虛函數可以聲明為内聯,但是編譯器一定不會響應内聯的請求。
8,字元數組的輸入
Q:
定義語句:
int b;
char c[10];
則正确的輸入語句為?
A:
- scanf("%d%s", &b, &c);
- scanf("%d%s", &b, &c);
對于一個在棧上配置設定的數組,且在建立的代碼塊中進行通路的化,“c”實際上有兩種含義:
- 一個指向十個char類型元素的數組;
- 一個char* 類型的指針。
對于第一種而言,對其進行sizeof©操作,得到的結果為10。
那麼,何時是第一種,何時是第二種呢?
實際上,第二種是第一種的一種文法糖,是語言設計這為了友善而下放的一個空子。這種文法糖,在二維數組及以上就不成立了。
這就是所謂的上下文語義(編譯器的語義)。
- scanf("%s", c); //這裡c是一個char* 類型的指針,編譯器相信程式員将它指向了一塊記憶體塊;
- scanf("%s", &c); //這裡c是一個指向十個char元素的數組的指針,這種才是最正統的用法。
9,宏定義與文法檢查
宏定義不做文法檢查。
預處理是在編譯之前的處理,而編譯的工作之一就是文法檢查,是以預處理并不做文法檢查。
隻有當調用這個宏定義時才會去檢查定義是否正确。
10,拷貝構造函數的調用
拷貝構造函數的調用時機:
- 當用類的一個對象初始化類的另一個對象時;
- 如果函數的形參是類的對象,調用函數時,進行形參和實參的結合;
- 如果函數的傳回值是類的對象,函數執行完成傳回調用者時;
- 需要産生一個臨時類對象時;