這篇文章主要為大家展示了“Thinking in C++重點(diǎn)知識(shí)有哪些”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Thinking in C++重點(diǎn)知識(shí)有哪些”這篇文章吧。

專(zhuān)注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)汕頭免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
解釋器(interpreter)
編譯器(complier)
預(yù)處理器(preprocessor)處理預(yù)處理指令
編譯分為兩遍,第一遍解析預(yù)處理代碼生成節(jié)點(diǎn)數(shù),在進(jìn)行第二步之前進(jìn)行全局優(yōu)化(global optimizer),第二遍代碼生成器(code generator)解析代碼樹(shù)生成機(jī)器語(yǔ)言或者匯編語(yǔ)言
靜態(tài)類(lèi)型檢查在第一遍中進(jìn)行
void function();//聲明void function(){}//定義extern int a;//聲明int a;//定義編譯過(guò)程的最后階段,把編譯器生成的目標(biāo)模塊連接成可執(zhí)行文件(操作系統(tǒng)可以識(shí)別)
return語(yǔ)句退出函數(shù),返回到函數(shù)調(diào)用后的那點(diǎn),聯(lián)想棧的操作
由庫(kù)管理器來(lái)管理對(duì)象模塊,這個(gè)庫(kù)管理器就是管理.lib/.a文件的
for(initialization;conditional;step)
for循環(huán)首先執(zhí)行initialization,其次判斷conditional,滿足則進(jìn)入循環(huán),執(zhí)行完循環(huán)進(jìn)行step步驟
switch(selector){
case integral-value:statement;break; ...
defualt:statement;
}switch中的selector必須為整數(shù)值,integral-value必須為整形數(shù)值
selector也可以為enum類(lèi)型值
用于改變基本內(nèi)建類(lèi)型的含義并將基本類(lèi)型擴(kuò)展成一個(gè)更大的集合
1. int: short int / int / long int(使用short和long時(shí),int關(guān)鍵字可以省略)
2. float/double: 沒(méi)有l(wèi)ong float只有l(wèi)ong double,即:float / double /long double
3. signed/unsigned:符號(hào)位(適用于整形和字符型)
void*指針可以賦值為任何類(lèi)型的地址,但是會(huì)丟失類(lèi)型信息,不恰當(dāng)?shù)念?lèi)型轉(zhuǎn)換會(huì)導(dǎo)致程序崩潰
從定義點(diǎn)開(kāi)始,到和定義變量之前最鄰近的開(kāi)括號(hào)配對(duì)的第一個(gè)閉括號(hào),也就是說(shuō)作用域由變量所在的最近一對(duì)括號(hào)確定。
全局變量的生命周期一直到程序結(jié)束,可以使用extern關(guān)鍵字來(lái)使用另一個(gè)文件中的全局變量
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ò)誤內(nèi)部連接:只對(duì)正在編譯的文件穿件存儲(chǔ)空間,為每一個(gè)標(biāo)識(shí)符創(chuàng)建單獨(dú)的存儲(chǔ)空間,內(nèi)部連接由關(guān)鍵字static指定
外部連接:對(duì)所有編譯過(guò)的文件創(chuàng)建一個(gè)單獨(dú)的存儲(chǔ)空間,即將所有變量和函數(shù)包含在該空間中
自動(dòng)(局部)變量只是臨時(shí)存在于堆棧中,連接器不知道自動(dòng)變量,所以這些變量沒(méi)有連接
#define PRINT(STR,VAR) \ cout << STR << VAR << endl; \ cout << VAR << STR <<endl 即可以像調(diào)用函數(shù)一樣調(diào)用PRINT,這里預(yù)處理宏分行使用'\',宏只是展開(kāi),并替換 #define PRINT(STR,VAR) \ cout << #STR << VAR << endl 這里'#'表示STR字符串化(stringizing),比如:int i = 0;PRINT(i,i); //這里輸出應(yīng)該是 i:0
typedef existing-type-description alias-name
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類(lèi)型轉(zhuǎn)換為int,然后自增1之后,將該值在轉(zhuǎn)換成color,第二次轉(zhuǎn)換時(shí)非法的
使用friend關(guān)鍵字可以訪問(wè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的全部定義以確定它的大小以及如何傳遞,使用不完全類(lèi)型說(shuō)明(incomplete type specification),即在struct Y之前聲明struct X;
嵌套結(jié)構(gòu)不能自動(dòng)獲得訪問(wèn)private成員權(quán)限,可以使用如下方法訪問(wè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);
...
}//: Hadler.h
class Handler{
struct Cheshire;
Cheshire* smile;
public: ...};
//:~
//:Handler.cpp
struct Handler::Cheshire{
int i; ...}...Handler.h文件中struct Cheshire是一個(gè)不完全的類(lèi)型說(shuō)明或者類(lèi)聲明,具體類(lèi)定義放在了實(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;
}上述代碼報(bào)錯(cuò)
switch回跳過(guò)構(gòu)造函數(shù)的的序列點(diǎn),甚至構(gòu)造函數(shù)沒(méi)有被調(diào)用時(shí),這個(gè)對(duì)象也會(huì)在后面的 程序塊中程序塊中起作用,這里產(chǎn)生錯(cuò)誤
是確保對(duì)象在產(chǎn)生的同時(shí)被初始化。goto也會(huì)產(chǎn)生這樣的錯(cuò)誤。
當(dāng)void*指向一個(gè)非內(nèi)建類(lèi)型的對(duì)象時(shí),只會(huì)釋放內(nèi)存,不會(huì)執(zhí)行析構(gòu)函數(shù)
class Object{public: Object(int number);private: int m_number;
};Object object[2] = {Object{1}};Object沒(méi)有默認(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)沒(méi)有構(gòu)造函數(shù)時(shí)編譯器會(huì)自動(dòng)創(chuàng)建一個(gè)默認(rèn)構(gòu)造函數(shù)
使用范圍和參數(shù)可以進(jìn)行重載
void f();class X{void f();};1.cppvoid functin(int);2.cppvoid function(char);int main(){ function(1); //cause a linker error;
return 0;
}編譯成功,在C中連接成功,但是在C++中連接出錯(cuò),這是C++中的一種機(jī)制:類(lèi)型安全連接
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 <<endl; break; case integer: cout << "integer :" << i <<endl; break; case floating_point: cout << "float :" << f <<endl; break;
}
}int main(){
SuperVar A('c'),B(12),C(1.44f);
A.print();
B.print();
C.print(); return 0;
}enum沒(méi)有類(lèi)型名,因?yàn)楹竺鏇](méi)有必要涉及美劇的類(lèi)型名稱(chēng),所以枚舉類(lèi)型名可選,非必須
union沒(méi)有類(lèi)型名和標(biāo)識(shí)符,稱(chēng)為匿名聯(lián)合(anonymous union),不需要使用標(biāo)識(shí)符和以點(diǎn)操作符方式訪問(wèn)這個(gè)union的元素
訪問(wèn)一個(gè)匿名聯(lián)合成員就像訪問(wèn)普通變量一樣,唯一區(qū)別在于:該聯(lián)合的兩個(gè)變量占用同一內(nèi)存空間,如果匿名union在文件作用域內(nèi)(在所有函數(shù)和類(lèi)之外),則它必須聲明為static,以使它有內(nèi)部的連接
只有參數(shù)列表的后部參數(shù)才可以是默認(rèn)的
一旦在一個(gè)函數(shù)調(diào)用中開(kāi)始使用默認(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ù)
C++中const默認(rèn)為內(nèi)部連接,僅在const被定義的文件中才可見(jiàn),在連接時(shí)不能被其它編譯單元看見(jiàn),當(dāng)定義一個(gè)const時(shí)必須賦值給它,除非使用extern進(jìn)行說(shuō)明
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修飾指針正指向的對(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的寫(xiě)法允許對(duì)howdy進(jìn)行修改
在求表達(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}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()類(lèi)似,因?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;
}必須在構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化
一個(gè)內(nèi)建類(lèi)型的static const可以看成編譯期間的常量,但是該static const必須在定義的地方進(jìn)行初始化
無(wú)標(biāo)記enum也可以看成為編譯期間常量,一個(gè)枚舉在編譯期間必須有值
class X{
enum {size = 1000}; //same as static const
static const int size = 1000; int i[size];
}若將一個(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ù)牡胤较窈暌粯诱归_(kāi),不需要函數(shù)調(diào)用的開(kāi)銷(xiāo)(壓棧,出棧),任何在類(lèi)內(nèi)部定義的函數(shù)自動(dòng)成為內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)體過(guò)大時(shí),編譯器將放棄使用內(nèi)聯(lián)
當(dāng)取函數(shù)地址時(shí),編譯器也將放棄內(nèi)聯(lián)
一個(gè)內(nèi)聯(lián)函數(shù)在類(lèi)中向前引用一個(gè)還沒(méi)有聲明的函數(shù)時(shí),是可以的,因?yàn)镃++規(guī)定只有在類(lèi)聲明結(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;}
}class X
{ int i,j,k;public:
X(int x = 0):i(x),j(x),k(x) { cout << "X" <<endl;} //X(int x):i(x),j(x),k(x){cout << "X" <<endl;}
~X(){cout << "~X" <<endl;}
};class Y{
X q,r,s; int i;public:
Y(int ii):i(ii){cout << "Y" <<endl;}
~Y(){ cout << "~Y" <<endl;
}
};int main(int argc, char *argv[])
{
Y y(1); return 0;
}//:~//:outputX
X
X
Y
~Y
~X
~X
~X類(lèi)中包含子對(duì)象,構(gòu)造函數(shù)先調(diào)用子對(duì)象的構(gòu)造函數(shù),如果沒(méi)有默認(rèn)構(gòu)造函數(shù),則必須在初始化列表中進(jìn)行初始化,然后在調(diào)用類(lèi)的構(gòu)造函數(shù)
類(lèi)中包含子對(duì)象,先調(diào)用類(lèi)的析構(gòu)函數(shù)在調(diào)用子類(lèi)的析構(gòu)函數(shù)
1. #define DEBUG(x) cout << #x "=" << x<<endl;#:字符串化,詳見(jiàn)REF2. #define FIELD(a) char* a##_string;int a##_size##:標(biāo)志粘貼,允許設(shè)兩個(gè)標(biāo)識(shí)符并將它們粘貼在一起產(chǎn)生新的標(biāo)識(shí)符
在固定地址上進(jìn)行存儲(chǔ)分配,在一個(gè)特殊的靜態(tài)數(shù)據(jù)區(qū)上創(chuàng)建,不是在堆棧上產(chǎn)生
對(duì)一個(gè)特定編譯單位來(lái)說(shuō)是局部的,static可以控制名字的可見(jiàn)性,該名字在這個(gè)單元或者類(lèi)以外是不可見(jiàn)的
如果沒(méi)有為一個(gè)內(nèi)建類(lèi)型的靜態(tài)變量提供一個(gè)初始化值,編譯器會(huì)確保在程序開(kāi)始時(shí)它被初始化為零(轉(zhuǎn)化成適當(dāng)?shù)念?lèi)型)
如果在定義一個(gè)靜態(tài)對(duì)象時(shí)沒(méi)有指定構(gòu)造參數(shù)時(shí),該類(lèi)必須有默認(rèn)的構(gòu)造函數(shù)
常量、內(nèi)聯(lián)函數(shù)默認(rèn)情況下為內(nèi)部鏈接
所有全局對(duì)象隱含為靜態(tài)存儲(chǔ)
對(duì)static函數(shù)意味著只在本單元可見(jiàn),成為文件靜態(tài)(file static)
static成員必須在類(lèi)外初始化,如果不初始化,則編譯器不會(huì)進(jìn)行默認(rèn)初始化,對(duì)于非內(nèi)建類(lèi)型,可以使用構(gòu)造函數(shù)初始化代替“=”操作符
類(lèi)內(nèi)const成員必須在構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化
static const變量(內(nèi)建類(lèi)型)必須在聲明的地方就初始化
static對(duì)象數(shù)組,包括const和非const數(shù)組必須在類(lèi)外部初始化
自定義class類(lèi)聲明為stctic,不管其為const或者非const都必須在類(lèi)外初始化
類(lèi)的靜態(tài)成員必須進(jìn)行初始化后才可以使用
類(lèi)的靜態(tài)成員函數(shù)不能訪問(wèn)一般數(shù)據(jù)成員或者函數(shù),只能訪問(wèn)靜態(tài)數(shù)據(jù)成員,也能調(diào)用其他靜態(tài)成員函數(shù)
靜態(tài)成員函數(shù)沒(méi)有this指針
優(yōu)先級(jí)低的先讀
*p[] 指針數(shù)組
(*p)[] 數(shù)組指針,即指向一個(gè)數(shù)組
函數(shù)的地址:函數(shù)名后不跟參數(shù)
void fun(){}fun即為函數(shù)地址fun()為函數(shù)的調(diào)用double pam(int); //prototypedouble (*pf)(int); //function pointerpf=pam;//pf now points to the pam();
double x=pf(5);double x=(*pf)(5);
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)->返回 double
typedef const double* (*p_fun)(const double* ,int);
p_fun p1 = f1;
p_fun pa[3] = {f1,f2,f3};
p_fun (*pd)[3] = &pa;namespace只能在全局范圍內(nèi)定義,但是可以相互嵌套
在namespace定義的結(jié)尾,右花括號(hào)后面不必跟一個(gè)分號(hào)
可以按類(lèi)的語(yǔ)法來(lái)定義一個(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è)名字來(lái)作為它的別名
namespace lib = MyLib;
不能像類(lèi)一樣創(chuàng)建一個(gè)名字空間的實(shí)例
namespace {
class A{};
class B{};
int i,j,k;
//...}將局部名字放在一個(gè)未命名的名字空間中,不需要加上static就可以作為內(nèi)部連接
using directive:using namespace xxusing declaration:using xx::f;
new計(jì)算內(nèi)存大小,并調(diào)用構(gòu)造函數(shù),malloc需要手工計(jì)算內(nèi)存大小,不調(diào)用構(gòu)造函數(shù)
delete先執(zhí)行析構(gòu)函數(shù),在清空內(nèi)存,free直接清空內(nèi)存
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ì)象的指針,如果沒(méi)有找到存儲(chǔ)單元,則返回一個(gè)0,然而如果找不到存儲(chǔ)單元,不能僅僅返回0,還應(yīng)該有new-handler或產(chǎn)生一個(gè)異常信息
new返回void*,而不是指向任何特定類(lèi)型的指針,只需要完成內(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 <cstdio>#include <cstdlib>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這里使用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來(lái)初始化自身
//p328
主要思想:使用static數(shù)組以及一個(gè)bool數(shù)組,返回static數(shù)組的下標(biāo)地址,進(jìn)行new,得到static下標(biāo)數(shù)組進(jìn)行delete
void* operator new(size_t) throw(bad_alloc);
void operator delete(void*);
//p331
//p333
主要思想:使用new運(yùn)算符重載,但是不對(duì)delete運(yùn)算符重載,指定內(nèi)存位置new
void* operator new(size_t,void*);
成員對(duì)象如果沒(méi)有默認(rèn)的構(gòu)造函數(shù),必須顯示的進(jìn)行初始化,即在構(gòu)造函數(shù)初始化列表中進(jìn)行初始化
只有執(zhí)行成員類(lèi)型初始化之后,才會(huì)進(jìn)入構(gòu)造函數(shù)
沒(méi)有對(duì)所有成員以及基類(lèi)對(duì)象的構(gòu)造函數(shù)調(diào)用之前,若基類(lèi)沒(méi)有默認(rèn)構(gòu)造函數(shù)則必須初始化,即在初始化列表中進(jìn)行初始化,否則無(wú)法進(jìn)入構(gòu)造函數(shù)體
構(gòu)造函數(shù)調(diào)用的順序:首先調(diào)用基類(lèi)構(gòu)造函數(shù),然后調(diào)用成員對(duì)象的構(gòu)造函數(shù),調(diào)用成員對(duì)象構(gòu)造函數(shù)的順序是按照成員對(duì)象在類(lèi)中聲明的順序執(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)用基類(lèi)析構(gòu)函數(shù)
對(duì)于多重繼承,構(gòu)造函數(shù)調(diào)用順序?yàn)槔^承時(shí)的聲明順序
構(gòu)造函數(shù)
析構(gòu)函數(shù)
operator=
靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的共同特點(diǎn):
1. 均可以被繼承到派生類(lèi)中
2. 重新定義一個(gè)靜態(tài)成員,所有基類(lèi)中的其他重載函數(shù)會(huì)被隱藏
3. 如果我們改變了基類(lèi)中的函數(shù)的特征,所有使用該函數(shù)名字的基類(lèi)版本將會(huì)被隱藏。
4. 靜態(tài)成員函數(shù)不可以是虛函數(shù)
使用私有繼承是為了不允許該對(duì)象的處理像一個(gè)基類(lèi)對(duì)象,一般private更適合于組合
私有繼承成員公有化
class Base{ public: Base(){}
~Base(){} void name() {cout << "Base name" <<endl;}
}
class Derived:private Base{ public: Derived(){}
~Derived(){} using Base::name; //私有繼承公有化}class Base{ public: Base(){}
Base(const Base&){}
~Base(){} void name() {cout << "Base name" <<endl;}
}
class Derived:public Base{ public: Derived(){}
Derived(const Derived& d):Base(d){ }//這里是調(diào)用基類(lèi)的拷貝構(gòu)造函數(shù)
~Derived(){}
}基類(lèi)拷貝構(gòu)造函數(shù)的調(diào)用將一個(gè)Derived引用向上類(lèi)型轉(zhuǎn)換成一個(gè)Base引用,并且使用它來(lái)執(zhí)行拷貝構(gòu)造函數(shù),向上類(lèi)型轉(zhuǎn)換是安全的
首先進(jìn)行自我檢查(是否對(duì)自身賦值),即this == &val,在進(jìn)行運(yùn)算,“=”運(yùn)算符只允許作為成員函數(shù)進(jìn)行重載
對(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ù)仍然按地址傳遞
返回值類(lèi)型取決于運(yùn)算符的具體含義,如果使用該運(yùn)算符產(chǎn)生一個(gè)新值,就需要產(chǎn)生一個(gè)作為返回對(duì)象的新對(duì)象。例如operator+必須生成一個(gè)操作數(shù)之和的對(duì)象,該對(duì)象作為一個(gè)常量通過(guò)返回值返回,所以作為一個(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ù),否則無(wú)法調(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){}對(duì)于友元函數(shù)重載來(lái)說(shuō),因?yàn)閭魅氲腛bject對(duì)象被改變,所以使用非常量引用
前綴通過(guò)引用返回,后綴通過(guò)值(臨時(shí)對(duì)象)返回,因?yàn)楹缶Y返回臨時(shí)對(duì)象,所以后綴通過(guò)常量值返回,前綴返回引用,如果希望可以繼續(xù)改變對(duì)象則返回引用,否則通過(guò)常量引用返回比較合適,這樣與后綴保持了一致性
作為常量通常通過(guò)傳值方式返回。考慮二元運(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)被定義為常量,所以無(wú)論是否返回值為常量都沒(méi)有關(guān)系。但是如果使用(a+b).f(),這里設(shè)返回值為常量規(guī)定了對(duì)于返回值只有常量成員函數(shù)才可以調(diào)用
返回值優(yōu)化通過(guò)傳值方式返回要?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;
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è)局部變量所以?xún)H需要一個(gè)普通的構(gòu)造函數(shù)調(diào)用(不需要拷貝構(gòu)造函數(shù)),且不會(huì)調(diào)用析構(gòu)函數(shù),效率高。這種方式被稱(chēng)為返回值優(yōu)化。
該運(yùn)算符必須是成員函數(shù),而且只接受一個(gè)參數(shù),可以返回一個(gè)引用,可以用于等號(hào)左側(cè)。
該運(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<<i++<<endl;} void g() const {cout<<j++<<endl;}
};int Obj::i = 47;int Obj::j = 11;class ObjContainer{ vector<obj* >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<<i++<<endl;} void g() const {cout<<j++<<endl;}
};int Obj::i = 47;int Obj::j = 11;class ObjContainer{ vector<obj* >a; public: void add(Obj* obj) {a.push_back(obj);} class SmartPointer; //聲明友元之前必須告知該類(lèi)存在
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);
}
};//p294
所有一元運(yùn)算符建議為成員
=()[]->->*必須為成員
+= -= /= *= ^= &= |= %= >>= <<=建議為成員
所有其他二元運(yùn)算符為非成員
//p301引用計(jì)數(shù)
構(gòu)造函數(shù)轉(zhuǎn)換:構(gòu)造函數(shù)能把另外一個(gè)類(lèi)型對(duì)象(或者引用)作為它的單個(gè)參數(shù),該構(gòu)造函數(shù)允許編譯器執(zhí)行自動(dòng)類(lèi)型轉(zhuǎn)換
運(yùn)算符轉(zhuǎn)換:運(yùn)算符重載,創(chuàng)建一個(gè)成員函數(shù),該函數(shù)通過(guò)關(guān)鍵字operator后跟隨想要轉(zhuǎn)換的類(lèi)型的方法,將當(dāng)前類(lèi)型轉(zhuǎn)換為希望的類(lèi)型,自動(dòng)類(lèi)型轉(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ò)誤:提供不止一種類(lèi)型的自動(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è)資訊頻道!
分享名稱(chēng):ThinkinginC++重點(diǎn)知識(shí)有哪些
當(dāng)前地址:http://chinadenli.net/article26/ppdgjg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、做網(wǎng)站、自適應(yīng)網(wǎng)站、靜態(tài)網(wǎng)站、企業(yè)建站、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)