這篇文章主要為大家展示了“Thinking in C++重點(diǎn)知識(shí)有哪些”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Thinking in C++重點(diǎn)知識(shí)有哪些”這篇文章吧。
專注于為中小企業(yè)提供網(wǎng)站制作、網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)德安免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。Thinking in C++ Chapter 2Translator:解釋器(interpreter)
編譯器(complier)
預(yù)處理器(preprocessor)處理預(yù)處理指令
編譯分為兩遍,第一遍解析預(yù)處理代碼生成節(jié)點(diǎn)數(shù),在進(jìn)行第二步之前進(jìn)行全局優(yōu)化(global optimizer),第二遍代碼生成器(code generator)解析代碼樹生成機(jī)器語言或者匯編語言
函數(shù)或者變量的聲明與定義靜態(tài)類型檢查在第一遍中進(jìn)行
void function();//聲明void function(){}//定義extern int a;//聲明int a;//定義連接
編譯過程的最后階段,把編譯器生成的目標(biāo)模塊連接成可執(zhí)行文件(操作系統(tǒng)可以識(shí)別)
Thinking in C++ Chapter 3函數(shù)返回說明return語句退出函數(shù),返回到函數(shù)調(diào)用后的那點(diǎn),聯(lián)想棧的操作
通常函數(shù)庫由庫管理器來管理對(duì)象模塊,這個(gè)庫管理器就是管理.lib/.a文件的
關(guān)于for循環(huán)的說明for(initialization;conditional;step)
for循環(huán)首先執(zhí)行initialization,其次判斷conditional,滿足則進(jìn)入循環(huán),執(zhí)行完循環(huán)進(jìn)行step步驟
switch說明switch(selector){ case integral-value:statement;break; ... defualt:statement; }
switch中的selector必須為整數(shù)值,integral-value必須為整形數(shù)值
說明符(specifier)selector也可以為enum類型值
用于改變基本內(nèi)建類型的含義并將基本類型擴(kuò)展成一個(gè)更大的集合
1. int: short int / int / long int(使用short和long時(shí),int關(guān)鍵字可以省略)
2. float/double: 沒有l(wèi)ong float只有l(wèi)ong double,即:float / double /long double
3. signed/unsigned:符號(hào)位(適用于整形和字符型)
void*指針可以賦值為任何類型的地址,但是會(huì)丟失類型信息,不恰當(dāng)?shù)念愋娃D(zhuǎn)換會(huì)導(dǎo)致程序崩潰
變量的有效作用域從定義點(diǎn)開始,到和定義變量之前最鄰近的開括號(hào)配對(duì)的第一個(gè)閉括號(hào),也就是說作用域由變量所在的最近一對(duì)括號(hào)確定。
全局變量全局變量的生命周期一直到程序結(jié)束,可以使用extern關(guān)鍵字來使用另一個(gè)文件中的全局變量
靜態(tài)(static)變量static變量?jī)?yōu)點(diǎn)是在函數(shù)范圍之外它是不可用的,不可以輕易改變,使錯(cuò)誤局部化,當(dāng)應(yīng)用static于函數(shù)名和所有函數(shù)外部變量時(shí),它的意思是“在文件的外部不可以使用該名字”,即擁有文件作用域如
//file1.cppstatic int fs;int main(){ fs = 1; }//file2.cppextern int fs;//編譯器不會(huì)找到file1.cpp文件中的fs,即文件作用域void function(){ fs = 100; }
extern static int i;int main(){ cout << i << endl; }static int i = 0; 將出現(xiàn)error,即全局靜態(tài)變量聲明是有文件作用域的,編譯器將會(huì)產(chǎn)生錯(cuò)誤連接(linkage種類)
內(nèi)部連接:只對(duì)正在編譯的文件穿件存儲(chǔ)空間,為每一個(gè)標(biāo)識(shí)符創(chuàng)建單獨(dú)的存儲(chǔ)空間,內(nèi)部連接由關(guān)鍵字static指定
外部連接:對(duì)所有編譯過的文件創(chuàng)建一個(gè)單獨(dú)的存儲(chǔ)空間,即將所有變量和函數(shù)包含在該空間中
自動(dòng)(局部)變量只是臨時(shí)存在于堆棧中,連接器不知道自動(dòng)變量,所以這些變量沒有連接
#define PRINT(STR,VAR) \ cout << STR << VAR << endl; \ cout << VAR << STR <typedef語法說明 typedef existing-type-description alias-name
enum說明:
typedef unsinged long ulong;
typedef int* intPtr
typedef struct MyStruct{
//這里是C常營(yíng)的結(jié)構(gòu)定義
} MyStruct;typedef int (*fun)(int,int) //函數(shù)指針別名為fun
c++中對(duì)enum的檢查更為嚴(yán)格,c中允許a++(a為color型枚舉),但是c++中不允許,因?yàn)閍++做了兩次轉(zhuǎn)換,首先將color類型轉(zhuǎn)換為int,然后自增1之后,將該值在轉(zhuǎn)換成color,第二次轉(zhuǎn)換時(shí)非法的
Thinking in C++ Chapter 5友元使用friend關(guān)鍵字可以訪問內(nèi)部私有成員變量或者成員函數(shù)
struct X;struct Y{ void f(X*); };struct X{ private: int i; public: void initialize(); friend void g(X*,int); //Global friend friend void Y::f(X*); //struct member friend friend struct z; //Entire struct is a friend friend void h(); }嵌套友元Y::f(X*)引用了一個(gè)X對(duì)象的地址,編譯器知道如何傳遞一個(gè)地址,不管被傳遞的是什么對(duì)象,地址具有固定大小,當(dāng)試圖傳遞整個(gè)對(duì)象時(shí),編譯器必須知道X的全部定義以確定它的大小以及如何傳遞,使用不完全類型說明(incomplete type specification),即在struct Y之前聲明struct X;
嵌套結(jié)構(gòu)不能自動(dòng)獲得訪問private成員權(quán)限,可以使用如下方法訪問
聲明嵌套結(jié)構(gòu)
聲明該結(jié)構(gòu)是全局范圍內(nèi)使用的一個(gè)friend
定義該結(jié)構(gòu)
const in sz = 20;struct Holder{ private: int a[sz]; public: void initialize(); struct Pointer; friend Pointer; struct Pointer{ private: Holder* h; int* p; public: void initialize(Holder* h); void next(); void previous(); void top(); void end(); int read(); void set(int i); }; };void Holder::initialize(){ memset(a,0,sz*sizeof(int)); }void Holder::Pointer::initialize(Holder* rv){ h = rv; p = rv->a; } ...int main(){ Hodler h; Holder::Pointer hp; int i; h.initialize(); hp.initialize(&h); ... }struct其他//: Hadler.h class Handler{ struct Cheshire; Cheshire* smile; public: ...}; //:~ //:Handler.cpp struct Handler::Cheshire{ int i; ...}...Thinking in C++ Chapter 6構(gòu)造函數(shù)相應(yīng)說明Handler.h文件中struct Cheshire是一個(gè)不完全的類型說明或者類聲明,具體類定義放在了實(shí)現(xiàn)文件中
class Object{public: Object(int number = 0);private: int m_number; };//:~//: mainint main(int argc, char *argv[]) { int i = 0; switch(i){ case 0: Object obj1{1}; break; case 1: //error: cannot jump from switch statement to this case label "case 1:" Object obj2{2}; //jump bypasses variable initialization "Object obj1{1};" break; } return 0; }delete void*上述代碼報(bào)錯(cuò)
switch回跳過構(gòu)造函數(shù)的的序列點(diǎn),甚至構(gòu)造函數(shù)沒有被調(diào)用時(shí),這個(gè)對(duì)象也會(huì)在后面的 程序塊中程序塊中起作用,這里產(chǎn)生錯(cuò)誤
是確保對(duì)象在產(chǎn)生的同時(shí)被初始化。goto也會(huì)產(chǎn)生這樣的錯(cuò)誤。當(dāng)void*指向一個(gè)非內(nèi)建類型的對(duì)象時(shí),只會(huì)釋放內(nèi)存,不會(huì)執(zhí)行析構(gòu)函數(shù)
默認(rèn)構(gòu)造函數(shù)class Object{public: Object(int number);private: int m_number; };Object object[2] = {Object{1}};Thinking in C++ Chapter 7overloadObject沒有默認(rèn)構(gòu)造函數(shù),數(shù)組聲明初始化時(shí)將報(bào)錯(cuò),object[1]必須有默認(rèn)構(gòu)造函數(shù)進(jìn)行初始化,否則報(bào)錯(cuò)當(dāng)且僅當(dāng)沒有構(gòu)造函數(shù)時(shí)編譯器會(huì)自動(dòng)創(chuàng)建一個(gè)默認(rèn)構(gòu)造函數(shù)
使用范圍和參數(shù)可以進(jìn)行重載
void f();class X{void f();};類型安全連接(type-safe linkage)1.cppvoid functin(int);2.cppvoid function(char);int main(){ function(1); //cause a linker error; return 0; }Union編譯成功,在C中連接成功,但是在C++中連接出錯(cuò),這是C++中的一種機(jī)制:類型安全連接
class SuperVar{ enum{ character, integer, floating_point } vartype; union{ char c; int i; float f; }; public: SuperVal(char ch); SuperVal(int ii); SuperVal(float ff); void print(); }; SuperVal::SuperVali(char ch){ vartype = character; c = ch; } SuperVal::SuperVali(int ii){ vartype = integer; i = ii; } SuperVal::SuperVali(float ff){ vartype = floating_type; f = ff; }void SuperVal::print(){ switch(vartype){ case character: cout << "character:" << c <默認(rèn)參數(shù)使用規(guī)則:
enum沒有類型名,因?yàn)楹竺鏇]有必要涉及美劇的類型名稱,所以枚舉類型名可選,非必須
union沒有類型名和標(biāo)識(shí)符,稱為匿名聯(lián)合(anonymous union),不需要使用標(biāo)識(shí)符和以點(diǎn)操作符方式訪問這個(gè)union的元素
訪問一個(gè)匿名聯(lián)合成員就像訪問普通變量一樣,唯一區(qū)別在于:該聯(lián)合的兩個(gè)變量占用同一內(nèi)存空間,如果匿名union在文件作用域內(nèi)(在所有函數(shù)和類之外),則它必須聲明為static,以使它有內(nèi)部的連接
占位符參數(shù)
只有參數(shù)列表的后部參數(shù)才可以是默認(rèn)的
一旦在一個(gè)函數(shù)調(diào)用中開始使用默認(rèn)參數(shù),那么這個(gè)參數(shù)后面的所有參數(shù)都必須為默認(rèn)的
void f(int i, int = 0, float = 1.1); //version 1void f(int i ,int , float flt); // version 2其中version 2除了i,flt之外中間參數(shù)就是占位符參數(shù)
Thinking in C++ Chapter 8const說明C++中const默認(rèn)為內(nèi)部連接,僅在const被定義的文件中才可見,在連接時(shí)不能被其它編譯單元看見,當(dāng)定義一個(gè)const時(shí)必須賦值給它,除非使用extern進(jìn)行說明
extern const int bufsize;
通常c++不為const創(chuàng)建空間,將其定義保存在符號(hào)表內(nèi),但是上面的extern進(jìn)行了強(qiáng)制內(nèi)存空間分配,另外如取const的地址也是需要存儲(chǔ)空間的分配。
對(duì)于復(fù)雜的結(jié)構(gòu),編譯器建立存儲(chǔ),阻止常量折疊。在C中const默認(rèn)為外部連接,C++默認(rèn)為內(nèi)部連接.出現(xiàn)在所有函數(shù)外部的const作用域是整個(gè)文件,默認(rèn)為內(nèi)部連接
const指針賦值和類型檢查
const修飾指針正指向的對(duì)象 const int* a;
const修飾在指針中的地址 int* const a;
const對(duì)象地址不可以賦值給一個(gè)非const指針,但是可以吧一個(gè)非const對(duì)象地址賦值給一個(gè)const指針
字符數(shù)據(jù)的字面值:
char * cp = "howdy";char cp[] = "howdy";指針cp指向一個(gè)常量值,即常量字符數(shù)組,數(shù)組cp的寫法允許對(duì)howdy進(jìn)行修改
臨時(shí)變量在求表達(dá)式值期間,編譯器必須創(chuàng)建零時(shí)變量,編譯器為所有的臨時(shí)變量自動(dòng)生成為const
傳遞和返回地址void t(int*) {}void u(const int* clip){ //*clip = 2; error int i = *clip; //int * ip2 = clip error;}const char* v(){ return "result of functin 0"; }const int * const w(){ static int i; return &i; }int main(){ int x= 0; int * ip = &x; const int * cip = &x; t(ip); //ok //t(cip); not ok; u(ip); //ok u(cip);//ok //char * cp = v(); not ok const char* ccp = v();//ok //int * ip2 = w(); not ok const int * const ccip = w();// ok const int* cip2 = w();//ok //*w() = 1; not ok}標(biāo)準(zhǔn)參數(shù)傳遞
const指針不可以賦值給非const指針,但是非const指針可以賦值給const指針
函數(shù)v()返回一個(gè)從字符數(shù)組的字面值中建立的const char *,在編譯器建立了它并把它存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)之后,該聲明實(shí)際上產(chǎn)生該字符數(shù)組的字面值的地址
函數(shù)w()返回值要求這個(gè)指針以及這個(gè)指針?biāo)赶虻膶?duì)象均為常量,與函數(shù)v()類似,因?yàn)閕是靜態(tài)的,所以函數(shù)返回后返回值仍然有效
const int* const w()只有在作左值時(shí)第二個(gè)const才能顯現(xiàn)作用,所以w()返回值可以賦值給const int *
可以將臨時(shí)對(duì)象傳遞給const引用,但不能將一個(gè)臨時(shí)對(duì)象傳遞給接收指針的函數(shù),對(duì)于指針必須明確接受地址(臨時(shí)變量總是const)
class X {public: X() {} }; X f(){return X();}void g1(X&){ }void g2(const X&){ }int main(int argc, char *argv[]) { g1(f()); //error! g2(f()); return 0; }類內(nèi)數(shù)據(jù)成員為const初始化必須在構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化
編譯期間的常量
一個(gè)內(nèi)建類型的static const可以看成編譯期間的常量,但是該static const必須在定義的地方進(jìn)行初始化
無標(biāo)記enum也可以看成為編譯期間常量,一個(gè)枚舉在編譯期間必須有值
class X{ enum {size = 1000}; //same as static const static const int size = 1000; int i[size]; }const對(duì)象和成員函數(shù)Thinking in C++ Chapter 9內(nèi)聯(lián)函數(shù)
若將一個(gè)成員函數(shù)聲明為const,則該成員函數(shù)可以被const對(duì)象調(diào)用
const成員函數(shù)可以調(diào)用非const成員和const成員,非const成員函數(shù)同樣可以使用const成員
const對(duì)象只能調(diào)用const成員函數(shù),非const對(duì)象調(diào)用非const成員函數(shù)
內(nèi)聯(lián)函數(shù)與普通函數(shù)一樣執(zhí)行,但是內(nèi)聯(lián)函數(shù)在適當(dāng)?shù)牡胤较窈暌粯诱归_,不需要函數(shù)調(diào)用的開銷(壓棧,出棧),任何在類內(nèi)部定義的函數(shù)自動(dòng)成為內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)體過大時(shí),編譯器將放棄使用內(nèi)聯(lián)
當(dāng)取函數(shù)地址時(shí),編譯器也將放棄內(nèi)聯(lián)
一個(gè)內(nèi)聯(lián)函數(shù)在類中向前引用一個(gè)還沒有聲明的函數(shù)時(shí),是可以的,因?yàn)镃++規(guī)定只有在類聲明結(jié)束后,其中的內(nèi)聯(lián)函數(shù)才會(huì)被計(jì)算
class Forward{ int i; public: Forward():i(0){} int f() const {return g()+i;} int g() const {return i;} }構(gòu)造函數(shù)和析構(gòu)函數(shù)隱藏行為class X { int i,j,k;public: X(int x = 0):i(x),j(x),k(x) { cout << "X" <預(yù)處理器
類中包含子對(duì)象,構(gòu)造函數(shù)先調(diào)用子對(duì)象的構(gòu)造函數(shù),如果沒有默認(rèn)構(gòu)造函數(shù),則必須在初始化列表中進(jìn)行初始化,然后在調(diào)用類的構(gòu)造函數(shù)
類中包含子對(duì)象,先調(diào)用類的析構(gòu)函數(shù)在調(diào)用子類的析構(gòu)函數(shù)
1. #define DEBUG(x) cout << #x "=" << x<Thinking in C++ Chapter 10static static對(duì)象
在固定地址上進(jìn)行存儲(chǔ)分配,在一個(gè)特殊的靜態(tài)數(shù)據(jù)區(qū)上創(chuàng)建,不是在堆棧上產(chǎn)生
對(duì)一個(gè)特定編譯單位來說是局部的,static可以控制名字的可見性,該名字在這個(gè)單元或者類以外是不可見的
內(nèi)部鏈接
如果沒有為一個(gè)內(nèi)建類型的靜態(tài)變量提供一個(gè)初始化值,編譯器會(huì)確保在程序開始時(shí)它被初始化為零(轉(zhuǎn)化成適當(dāng)?shù)念愋?
如果在定義一個(gè)靜態(tài)對(duì)象時(shí)沒有指定構(gòu)造參數(shù)時(shí),該類必須有默認(rèn)的構(gòu)造函數(shù)
常量、內(nèi)聯(lián)函數(shù)默認(rèn)情況下為內(nèi)部鏈接
othersstactic/const/stctic const
所有全局對(duì)象隱含為靜態(tài)存儲(chǔ)
對(duì)static函數(shù)意味著只在本單元可見,成為文件靜態(tài)(file static)
靜態(tài)成員函數(shù)
static成員必須在類外初始化,如果不初始化,則編譯器不會(huì)進(jìn)行默認(rèn)初始化,對(duì)于非內(nèi)建類型,可以使用構(gòu)造函數(shù)初始化代替“=”操作符
類內(nèi)const成員必須在構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化
static const變量(內(nèi)建類型)必須在聲明的地方就初始化
static對(duì)象數(shù)組,包括const和非const數(shù)組必須在類外部初始化
自定義class類聲明為stctic,不管其為const或者非const都必須在類外初始化
類的靜態(tài)成員必須進(jìn)行初始化后才可以使用
指針數(shù)組/數(shù)組指針
類的靜態(tài)成員函數(shù)不能訪問一般數(shù)據(jù)成員或者函數(shù),只能訪問靜態(tài)數(shù)據(jù)成員,也能調(diào)用其他靜態(tài)成員函數(shù)
靜態(tài)成員函數(shù)沒有this指針
優(yōu)先級(jí)低的先讀
函數(shù)指針函數(shù)地址(Function Address)
*p[] 指針數(shù)組
(*p)[] 數(shù)組指針,即指向一個(gè)數(shù)組函數(shù)的地址:函數(shù)名后不跟參數(shù)
void fun(){}fun即為函數(shù)地址fun()為函數(shù)的調(diào)用函數(shù)指針double pam(int); //prototypedouble (*pf)(int); //function pointerpf=pam;//pf now points to the pam();調(diào)用函數(shù)指針double x=pf(5);double x=(*pf)(5);函數(shù)指針數(shù)組const double* f1(const double ar[],int n);const double* f2(const double [],int);const double* f3(coanst double *,int);//f1,f2,f3函數(shù)聲明本質(zhì)一樣const double* (*pa[3])(const double * , int) = {f1,f2,f3}; //[]優(yōu)先級(jí)高于*,所以表示pa是個(gè)數(shù)組,數(shù)組中包含三個(gè)指針auto pb = pa;const double * px = pa[0](av,3);const double * py = (*pb[1])(av,3);double x = *pa[0](av,3);double y = *(pb[1])(av,3);指向整個(gè)數(shù)組的指針,即是一個(gè)指針,而不是一個(gè)數(shù)組,優(yōu)先級(jí)低的先讀
*p[] 指針數(shù)組
(*p)[] 數(shù)組指針,即指向一個(gè)數(shù)組const double* (*(*pd)[3])(const double* , int) = &pa;->等價(jià)形式 auto pd = &pa;pd指向數(shù)組,*pd就是數(shù)組,而(*pd)[i]是數(shù)組中的元素,即函數(shù)指針
函數(shù)調(diào)用:(*pd)[i](av,3)->此處返回const double * *(*pd)[i](av,3)->此處返回 double 另外一種函數(shù)調(diào)用略復(fù)雜(*(*pd)[i])(av,3)->返回const double * *(*(*pd)[i])(av,3)->返回 doubletypedef簡(jiǎn)化工作量typedef const double* (*p_fun)(const double* ,int); p_fun p1 = f1; p_fun pa[3] = {f1,f2,f3}; p_fun (*pd)[3] = &pa;namespacenamespace
namespace只能在全局范圍內(nèi)定義,但是可以相互嵌套
在namespace定義的結(jié)尾,右花括號(hào)后面不必跟一個(gè)分號(hào)
可以按類的語法來定義一個(gè)namespace,定義的內(nèi)容可以在多個(gè)頭文件中延續(xù),就好像重復(fù)定義這個(gè)namespace
//:header1.h namespace MyLib{ extern int x; void f(); //...} //:~ //:header2.h namespace MyLib{ extern int y; void g(); //...}未命名的名字空間
一個(gè)namespace的名字可以用另一個(gè)名字來作為它的別名
namespace lib = MyLib;不能像類一樣創(chuàng)建一個(gè)名字空間的實(shí)例
namespace { class A{}; class B{}; int i,j,k; //...}將局部名字放在一個(gè)未命名的名字空間中,不需要加上static就可以作為內(nèi)部連接
using directive& using declarationusing directive:using namespace xxusing declaration:using xx::f;new/malloc/delete/freenew/mallocnew計(jì)算內(nèi)存大小,并調(diào)用構(gòu)造函數(shù),malloc需要手工計(jì)算內(nèi)存大小,不調(diào)用構(gòu)造函數(shù)
delete/freedelete先執(zhí)行析構(gòu)函數(shù),在清空內(nèi)存,free直接清空內(nèi)存
重載全局new和delete
delete用于void*時(shí)將不會(huì)調(diào)用析構(gòu)函數(shù),直接清空內(nèi)存
重載的new必須有一個(gè)size_t參數(shù),該參數(shù)由編譯器產(chǎn)生并傳遞給我們,分配內(nèi)存的長(zhǎng)度,必須返回一個(gè)指向等于該長(zhǎng)度的對(duì)象的指針,如果沒有找到存儲(chǔ)單元,則返回一個(gè)0,然而如果找不到存儲(chǔ)單元,不能僅僅返回0,還應(yīng)該有new-handler或產(chǎn)生一個(gè)異常信息
new返回void*,而不是指向任何特定類型的指針,只需要完成內(nèi)存分配,而不是完成對(duì)象的創(chuàng)建,直到構(gòu)造函數(shù)調(diào)用才能完成對(duì)象的創(chuàng)建,調(diào)用構(gòu)造函數(shù)是編譯器完成的
delete參數(shù)是由new分配的void*指針,該參數(shù)是在調(diào)用析構(gòu)函數(shù)后得到的指針,析構(gòu)函數(shù)從存儲(chǔ)單元中移去對(duì)象
#include#include using namespace std;void* operator new(size_t sz){ printf("operator new:%d Bytes\n",sz); void* m = malloc(sz); if(!m) puts("out of memry"); return m; }void operator delete(void* m){ puts("operator delete"); free(m); }class S{ int i[100];public: S(){puts("S::S()");} ~S(){puts("S::~S()");} };int main(int argc, char *argv[]) { int * p = new int(47); delete p; S* s = new S; delete s; S* sa = new S[3]; delete [] sa; return 0; }//:outputoperator new:4 Bytesoperator deleteoperator new:400 Bytes S::S() S::~S()operator deleteoperator new:1208 Bytes S::S() S::S() S::S() S::~S() S::~S() S::~S()operator delete 類重載new和delete這里使用printf(),puts()等函數(shù),而不是iostreams,因?yàn)槭褂胕ostreams對(duì)象時(shí)(全局對(duì)象cin,cout,cerr),調(diào)用new分配內(nèi)存,printf不會(huì)進(jìn)入死鎖狀態(tài),它不調(diào)用new來初始化自身
//p328
主要思想:使用static數(shù)組以及一個(gè)bool數(shù)組,返回static數(shù)組的下標(biāo)地址,進(jìn)行new,得到static下標(biāo)數(shù)組進(jìn)行delete
為數(shù)組重載new和delete
void* operator new(size_t) throw(bad_alloc);
void operator delete(void*);//p331
定位new/delete//p333
主要思想:使用new運(yùn)算符重載,但是不對(duì)delete運(yùn)算符重載,指定內(nèi)存位置new
繼承與組合(Inheritance&Composition)初始化表達(dá)式
void* operator new(size_t,void*);構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用的順序
成員對(duì)象如果沒有默認(rèn)的構(gòu)造函數(shù),必須顯示的進(jìn)行初始化,即在構(gòu)造函數(shù)初始化列表中進(jìn)行初始化
只有執(zhí)行成員類型初始化之后,才會(huì)進(jìn)入構(gòu)造函數(shù)
沒有對(duì)所有成員以及基類對(duì)象的構(gòu)造函數(shù)調(diào)用之前,若基類沒有默認(rèn)構(gòu)造函數(shù)則必須初始化,即在初始化列表中進(jìn)行初始化,否則無法進(jìn)入構(gòu)造函數(shù)體
非自動(dòng)繼承的函數(shù)
構(gòu)造函數(shù)調(diào)用的順序:首先調(diào)用基類構(gòu)造函數(shù),然后調(diào)用成員對(duì)象的構(gòu)造函數(shù),調(diào)用成員對(duì)象構(gòu)造函數(shù)的順序是按照成員對(duì)象在類中聲明的順序執(zhí)行,最后調(diào)用自己的構(gòu)造函數(shù)
析構(gòu)函數(shù)調(diào)用次序與構(gòu)造函數(shù)調(diào)用次序相反,先調(diào)用自己的析構(gòu)函數(shù),在調(diào)用成員函數(shù)的析構(gòu)函數(shù),最后調(diào)用基類析構(gòu)函數(shù)
對(duì)于多重繼承,構(gòu)造函數(shù)調(diào)用順序?yàn)槔^承時(shí)的聲明順序
繼承與靜態(tài)成員函數(shù)
構(gòu)造函數(shù)
析構(gòu)函數(shù)
operator=
靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的共同特點(diǎn):
私有繼承
1. 均可以被繼承到派生類中
2. 重新定義一個(gè)靜態(tài)成員,所有基類中的其他重載函數(shù)會(huì)被隱藏
3. 如果我們改變了基類中的函數(shù)的特征,所有使用該函數(shù)名字的基類版本將會(huì)被隱藏。
4. 靜態(tài)成員函數(shù)不可以是虛函數(shù)
使用私有繼承是為了不允許該對(duì)象的處理像一個(gè)基類對(duì)象,一般private更適合于組合
私有繼承成員公有化
class Base{ public: Base(){} ~Base(){} void name() {cout << "Base name" <向上類型轉(zhuǎn)換和拷貝構(gòu)造函數(shù) class Base{ public: Base(){} Base(const Base&){} ~Base(){} void name() {cout << "Base name" <基類拷貝構(gòu)造函數(shù)的調(diào)用將一個(gè)Derived引用向上類型轉(zhuǎn)換成一個(gè)Base引用,并且使用它來執(zhí)行拷貝構(gòu)造函數(shù),向上類型轉(zhuǎn)換是安全的
運(yùn)算符重載+=,-=,*=,/=,=等一類運(yùn)算符重載首先進(jìn)行自我檢查(是否對(duì)自身賦值),即this == &val,在進(jìn)行運(yùn)算,“=”運(yùn)算符只允許作為成員函數(shù)進(jìn)行重載
函數(shù)參數(shù)和返回值說明Prefix ++ & Postfix ++
對(duì)于任何函數(shù)參數(shù),如果僅需要從參數(shù)中讀而不改變它,默認(rèn)地應(yīng)當(dāng)做const引用傳遞。普通算數(shù)運(yùn)算符(像“+”,“-”)和bool運(yùn)算符不會(huì)改變參數(shù),所以const引用為主要傳遞方式,當(dāng)函數(shù)時(shí)成員函數(shù)時(shí),就轉(zhuǎn)換為const成員函數(shù)。只有會(huì)改變左側(cè)參數(shù)的運(yùn)算符賦值(如+=)和operator=,左側(cè)參數(shù)不是常量,但因參數(shù)將被改變,所以參數(shù)仍然按地址傳遞
返回值類型取決于運(yùn)算符的具體含義,如果使用該運(yùn)算符產(chǎn)生一個(gè)新值,就需要產(chǎn)生一個(gè)作為返回對(duì)象的新對(duì)象。例如operator+必須生成一個(gè)操作數(shù)之和的對(duì)象,該對(duì)象作為一個(gè)常量通過返回值返回,所以作為一個(gè)左值不會(huì)被改變
所有賦值運(yùn)算符均改變左值,為了使賦值結(jié)果能用于鏈?zhǔn)奖磉_(dá)式(如a=b=c),應(yīng)該能夠返回一個(gè)剛剛改變了的左值的引用。但該引用并非一定要是常量引用,如(a=b).f(),這里b賦值給a,a調(diào)用成員函數(shù)f,因此所有賦值運(yùn)算符的返回值對(duì)于左值應(yīng)該是非常量引用(如果是常量引用,則f成員函數(shù)必須為const函數(shù),否則無法調(diào)用該函數(shù),這與愿望相違背)
對(duì)于邏輯運(yùn)算符,人們至少希望得到一個(gè)int返回值,或者最好是bool值
成員函數(shù)
const Object& operator++(){}const Object operator++(int){}
友元函數(shù)
const Object& operator++(Object& obj){}const Object operator++(Object& obj,int){}常量傳值返回與返回值優(yōu)化對(duì)于友元函數(shù)重載來說,因?yàn)閭魅氲腛bject對(duì)象被改變,所以使用非常量引用
前綴通過引用返回,后綴通過值(臨時(shí)對(duì)象)返回,因?yàn)楹缶Y返回臨時(shí)對(duì)象,所以后綴通過常量值返回,前綴返回引用,如果希望可以繼續(xù)改變對(duì)象則返回引用,否則通過常量引用返回比較合適,這樣與后綴保持了一致性
作為常量通常通過傳值方式返回??紤]二元運(yùn)算符+,假設(shè)在表達(dá)式f(a+b)中使用,a+b的結(jié)果變?yōu)橐粋€(gè)臨時(shí)對(duì)象(Object),該對(duì)象被f()調(diào)用,因?yàn)樗鼮榕R時(shí)的,所以自動(dòng)被定義為常量,所以無論是否返回值為常量都沒有關(guān)系。但是如果使用(a+b).f(),這里設(shè)返回值為常量規(guī)定了對(duì)于返回值只有常量成員函數(shù)才可以調(diào)用
返回值優(yōu)化通過傳值方式返回要?jiǎng)?chuàng)建的的新對(duì)象時(shí),注意使用的形式,如operator+
version 1:return Object(lObj.i+rObj.i); version 2: Object tmp(lObj.i+rObj.i);return tmp;operator[]version 2將會(huì)發(fā)生三件事,首先創(chuàng)建tmp對(duì)象,然后調(diào)用拷貝構(gòu)造函數(shù)把tmp拷貝到外部返回值的存儲(chǔ)單元中,最后當(dāng)tmp在作用域的結(jié)尾時(shí)調(diào)用析構(gòu)函數(shù)
version 1編譯器直接將該對(duì)象創(chuàng)建在外部返回值的內(nèi)存單元,不是整的創(chuàng)建一個(gè)局部變量所以僅需要一個(gè)普通的構(gòu)造函數(shù)調(diào)用(不需要拷貝構(gòu)造函數(shù)),且不會(huì)調(diào)用析構(gòu)函數(shù),效率高。這種方式被稱為返回值優(yōu)化。該運(yùn)算符必須是成員函數(shù),而且只接受一個(gè)參數(shù),可以返回一個(gè)引用,可以用于等號(hào)左側(cè)。
operator->(指針間接引用運(yùn)算符)該運(yùn)算符一定是一個(gè)成員函數(shù),它必須返回一個(gè)對(duì)象(或者引用),該對(duì)象也有一個(gè)指針間接引用運(yùn)算符;或者必須返回一個(gè)指針,被用于選擇指針間接引用運(yùn)算符箭頭所指的內(nèi)容
class Obj{ static int i,j; public: void f() const {cout<a; public: void add(Obj* obj) {a.push_back(obj);} friend class SmartPointer; };class SmartPointer{ ObjContainer& oc; int index; public: SmartPointer(ObjContainer & obj):oc(obj){ index = 0; } bool operator++(){ if(index >= oc.a.size()) return false; if(oc.a[++index] == 0) return false; return true; } bool operator++(int){ return operator++(); } Obj* operator->() const{ return oc.a[index]; } };指針間接引用運(yùn)算符自動(dòng)的為用SmartPointer::operator->返回的Obj*調(diào)用成員函數(shù)
class Obj{ static int i,j; public: void f() const {cout<a; public: void add(Obj* obj) {a.push_back(obj);} class SmartPointer; //聲明友元之前必須告知該類存在 friend SmartPointer; class SmartPointer{ ObjContainer& oc; int index; public: SmartPointer(ObjContainer & obj):oc(obj){ index = 0; } bool operator++(){ if(index >= oc.a.size()) return false; if(oc.a[++index] == 0) return false; return true; } bool operator++(int){ return operator++(); } Obj* operator->() const{ return oc.a[index]; } }; SmartPointer begin(){ return SmartPointer(*this); } };operator->*//p294
運(yùn)算符成員函數(shù)基本方針copy-on-write
所有一元運(yùn)算符建議為成員
=()[]->->*必須為成員
+= -= /= *= ^= &= |= %= >>= <<=建議為成員
所有其他二元運(yùn)算符為非成員
//p301引用計(jì)數(shù)
自動(dòng)類型轉(zhuǎn)換
構(gòu)造函數(shù)轉(zhuǎn)換:構(gòu)造函數(shù)能把另外一個(gè)類型對(duì)象(或者引用)作為它的單個(gè)參數(shù),該構(gòu)造函數(shù)允許編譯器執(zhí)行自動(dòng)類型轉(zhuǎn)換
運(yùn)算符轉(zhuǎn)換:運(yùn)算符重載,創(chuàng)建一個(gè)成員函數(shù),該函數(shù)通過關(guān)鍵字operator后跟隨想要轉(zhuǎn)換的類型的方法,將當(dāng)前類型轉(zhuǎn)換為希望的類型,自動(dòng)類型轉(zhuǎn)換只發(fā)生在函數(shù)調(diào)用值中,而不在成員選擇期間
class Three{ int i; public: Three(int ii = 0,int = 0):i(ii){} }; class Four{ int x; public: Four(int xx):x(xx){} operator Three() const {return Three(x);} };void g(Three){}int main(){ Four four(1); g(four); g(1); }
二義性錯(cuò)誤
class Orange; class Apple{ public: operator Orange() const; }; class Orange{ public: Orange(Apple); };void f(Orange){}int main(){ Apple a; // f(a); error:二義性錯(cuò)誤}
扇出錯(cuò)誤:提供不止一種類型的自動(dòng)轉(zhuǎn)換
class Orange{};class Pear{};class Apple{ public: operator Orange() const; operator Pear() const; };void eat(Orange);void eat(Apple);int main(){ Apple a; //eat(a); error:扇出錯(cuò)誤}以上是“Thinking in C++重點(diǎn)知識(shí)有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前題目:ThinkinginC++重點(diǎn)知識(shí)有哪些-創(chuàng)新互聯(lián)
鏈接地址:http://weahome.cn/article/dihojc.html