C Primer讀書筆記

2022-08-02 04:48:10 字數 4619 閱讀 4703

前些日子開始看《c++ primer》,順便做一些筆記,既有書上的,也有自己理解的。

因為剛學c++不久,筆下難免有謬誤之處,行文更是凌亂;

所幸不是用來顯配的東西,發在linuxsir只是為了方便自己閱讀記憶,以防只顧上網忘了正事。

書看了不到一半,所以大約才寫了一半,慢慢補充。

****************************************=

const要注意的問題

1、下面是乙個幾乎所有人剛開始都會搞錯的問題:

已知:typedef char *cstring;

在以下宣告中,cstr的型別是什麼?

extern const cstring cstr;

錯誤答案:const char *cstr;

正確答案:char *const cstr;

錯誤在於將typedef當作巨集擴充套件。const 修飾cstr的型別。cstr是乙個指標,因此,這個定義宣告了cstr是乙個指向字元的const指標。

2、指標是const還是data為const?

辨別方法很簡單,如下:

**:

char *p="hello"; //non-const pointer, non-const data;

const char *p="hello"; // non-const pointer, const data;

char * const p="hello"; // const pointer , non-const data;

const char * const p="hello"; // const pointer, const data;

要注意的是,"hello"的型別是const char * ,按c++standard規則,char *p="hello" 是非法的(右式的const char* 不能轉換為左式的char *),違反了常量性。但是這種行為在c中實在太頻繁,因此c++standard對於這種初始化動作給予豁免。儘管如此,還是盡量避免這種用法。

3、const初始化的一些問題

const 物件必須被初始化:

**:

const int *pi=new int; // 錯誤,沒有初始化

const int *pi=new int(100); //正確

const int *pci=new const int[100]; //編譯錯誤,無法初始化用new表示式建立的內建型別陣列元素。

什麼時候需要copy constructor,copy assignment operator,destructor

注意,若class需要三者之一,那麼它往往需要三者。

當class的copy constructor內分配有一塊指向hcap的記憶體,需要由destructor釋放,那麼它也往往需要三者。

為什麼需要protected 訪問級別

有人認為,protected訪問級別允許派生類直接訪問基類成員,這破壞了封裝的概念,因此所有基類的實現細節都應該是private的;另外一些人認為,如果派生類不能直接訪問基類的成員,那麼派生類的實現將無法有足夠的效率供使用者使用,如果沒有protected,類的設計者將被迫把基類成員設定為public。

事實上,protected正是在高純度的封裝與效率之間做出的乙個良好折衷方案。

為什麼需要virtual member function又不能濫用virtual

若基類設計者把本應設計成virtual的成員函式設計成非virtual,則繼承類將無法實現改寫(overridden),給繼承類的實現帶來不便;

另一方面,一旦成員函式被設計成virtual,則該類的物件將額外增加虛擬指標(vptr)和虛擬**(vtbl),所以倘若出於方便繼承類 overridden的目的而使所有成員函式都為virtual,可能會影響效率,因為每個virtual成員函式都需付出動態分派的成本。而且 virtual成員函式不能內聯(inline),我們知道,內聯發生在編譯時刻,而虛函式在執行時刻才處理。對於那些小巧而被頻繁呼叫、與型別無關的函式,顯然不應該被設定成virtual。

關於引用的一些注意點

1、把函式引數宣告為陣列的引用:當函式引數是乙個陣列型別的引用時,陣列長度成為引數和實參型別的一部分,編譯器檢查陣列實參的長度和與在函式引數型別中指定的長度是否匹配。

**:

//引數為10個int陣列

void showarr(int (&arr)[10]);

void func()

//更靈活的實現,借助函式模板。下面是乙個顯示陣列內容的函式。

template void printarr(const type (& r_array)[size])

',如**:

label8: }

辦法是在冒號後面加乙個空語句(乙個';'即可),如

**:

label7: ;}

2、goto語句不能向前跳過如下宣告語句:

**:

goto label6;

int x=1; //錯誤,不能跳過該宣告!

cout<

但是,把int x=1; 改為int x; 則正確了。另外一種方法是:

**:goto label6;

}int main()

由於未命名名字空間的成員是程式實體,所以mesg()可以在程式整個執行期間被呼叫。但是,未命名名字空間成員只在特定的檔案中可見,在構成程式的其他檔案中是不可以見的。未命名名字空間的成員與被宣告為static的全域性實體具有類似的特性。在c中,被宣告為static的全域性實體在宣告它的檔案之外是不可見的。

using關鍵字

1、using宣告與using指示符:前者是宣告某名字空間內的乙個成員,後者是使用整個名字空間。例如:

**:

using cpp_primer::matrix; // ok,using宣告

using

namespace
cpp_primer; //ok,using指示符

2、該using指示符語句可以加在程式檔案的幾乎任何地方,包括檔案開頭(#include語句之前)、函式內部。不過用using指定的名字空間作用域(生命週期)受using語句所在位置的生命週期約束。如,函式內部使用「using namespace myspacename;」則 myspacename僅在該函式內部可見。

3、可以用using語句指定多個名字空間,使得多個名字空間同時可見。但這增加了名字汙染的可能性,而且只有在使用各名字空間相同成員時由多個using指示符引起的二義性錯誤才能被檢測到,這將給程式的檢測、擴充套件、移植帶來很大的隱患。因此,因該盡量使用using宣告而不是濫用using指示符。

過載函式

1、如果兩個函式的參數列中引數的個數或者型別不同,則認為這兩個函式是過載的。

如果兩個函式的返回型別和參數列精確匹配,則第二個宣告被視為第乙個的重複宣告,與引數名無關。如 void print(string& str)與void print(string&)是一樣的。

如果兩個函式的參數列相同,但是返回型別不同,則第二個宣告被視為第乙個的錯誤重複宣告,會標記為編譯錯誤。

如果在兩個函式的參數列中,只有預設實參不同,則第二個宣告被視為第乙個的重複宣告。如int max(int *ia,int sz)與int max(int *, int=10)。

引數名型別如果是由typedef提供的,並不算作新型別,而應該當作typedef的原型別。

當引數型別是const或者volatile時,分兩種情況:對於實參按值傳遞時,const、volatile修飾符可以忽略;對於把const、 volatile應用在指標或者引用引數指向的型別時,const、volatile修飾符對於過載函式的宣告是有作用的。例如:

**:

//ok,以下兩個宣告其實一樣

void func(int i);

void func(const int i);

//error,無法通過編譯,因為func函式被定義了兩次。

void func(int i){}

void func(const int i){}

//ok,宣告了不同的函式

void func2(int *);

void func2(const int *);

//ok,宣告了不同的函式

void func3(int&);

void func3(const int&);

2、鏈結指示符extern "c"只能指定過載函式集中的乙個函式。原因與內部名編碼有關,在大多數編譯器內部,每個函式明及其相關參數列都被作為乙個惟一的內部名編碼,一般的做法是把引數的個數和型別都進行編碼,然後將其附在函式名後面。但是這種編碼不使用於用鏈結指示符extern "c"宣告的函式,這就是為什麼在過載函式集合中只有乙個函式可以被宣告為extern "c"的原因,具有不同的參數列的兩個extern "c"的函式會被鏈結編輯器視為同一函式。例如,包含以下兩個宣告的程式是非法的。

**:

//error:乙個過載函式集中有兩個extern "c"函式

extern "c" void print(const char*);

extern "c" void print(int);

函式模板

1、定義函式模板:

**:

template [inline/extern] 

returntype functionname(funcparameters...)

C primer 讀書筆記

第2 章 變數和基本型別 1 變數直接初始化和變數 複製初始化 int ival 1024 direct initialization int ival 1024 copy initialization 初始化不是賦值 2 內建型別復 制初始化和直接初始化幾乎沒有區別 但 對類型別物件來 說,有些初...

C Primer讀書筆記

前些日子開始看 c primer 順便做一些筆記,既有書上的,也有自己理解的。因為剛學c 不久,筆下難免有謬誤之處,行文更是凌亂 所幸不是用來顯配的東西,發在linuxsir只是為了方便自己閱讀記憶,以防只顧上網忘了正事。書看了不到一半,所以大約才寫了一半,慢慢補充。const要注意的問題 1 下面...

C Primer讀書筆記

前些日子開始看 c primer 順便做一些筆記,既有書上的,也有自己理解的。因為剛學c 不久,筆下難免有謬誤之處,行文更是凌亂 所幸不是用來顯配的東西,發在linuxsir只是為了方便自己閱讀記憶,以防只顧上網忘了正事。書看了不到一半,所以大約才寫了一半,慢慢補充。const要注意的問題 1 下面...