ThinkinginC++重點(diǎn)知識(shí)有哪些-創(chuàng)新互聯(lián)

這篇文章主要為大家展示了“Thinking in C++重點(diǎn)知識(shí)有哪些”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(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)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。Thinking in C++ Chapter 2Translator:
  1. 解釋器(interpreter)

  2. 編譯器(complier)

編譯器編譯程序步驟:
  1. 預(yù)處理器(preprocessor)處理預(yù)處理指令

  2. 編譯分為兩遍,第一遍解析預(yù)處理代碼生成節(jié)點(diǎn)數(shù),在進(jìn)行第二步之前進(jìn)行全局優(yōu)化(global optimizer),第二遍代碼生成器(code generator)解析代碼樹生成機(jī)器語言或者匯編語言

靜態(tài)類型檢查在第一遍中進(jìn)行

函數(shù)或者變量的聲明與定義
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ù)值

selector也可以為enum類型值

說明符(specifier)

用于改變基本內(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*指針說明

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變量優(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種類)
  1. 內(nèi)部連接:只對(duì)正在編譯的文件穿件存儲(chǔ)空間,為每一個(gè)標(biāo)識(shí)符創(chuàng)建單獨(dú)的存儲(chǔ)空間,內(nèi)部連接由關(guān)鍵字static指定

  2. 外部連接:對(duì)所有編譯過的文件創(chuàng)建一個(gè)單獨(dú)的存儲(chǔ)空間,即將所有變量和函數(shù)包含在該空間中

    自動(dòng)(局部)變量只是臨時(shí)存在于堆棧中,連接器不知道自動(dòng)變量,所以這些變量沒有連接
預(yù)處理宏
#define PRINT(STR,VAR) \
    cout << STR << VAR << endl; \
    cout << VAR << STR <<endl

即可以像調(diào)用函數(shù)一樣調(diào)用PRINT,這里預(yù)處理宏分行使用'\',宏只是展開,并替換

#define PRINT(STR,VAR) \
    cout << #STR << VAR << endl

這里'#'表示STR字符串化(stringizing),比如:int i = 0;PRINT(i,i); //這里輸出應(yīng)該是 i:0
typedef語法說明

typedef existing-type-description alias-name

  1. typedef unsinged long ulong;

  2. typedef int* intPtr

  3. typedef struct MyStruct{
    //這里是C常營的結(jié)構(gòu)定義
    } MyStruct;

  4. typedef int (*fun)(int,int) //函數(shù)指針別名為fun

enum說明:

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)限,可以使用如下方法訪問

  1. 聲明嵌套結(jié)構(gòu)

  2. 聲明該結(jié)構(gòu)是全局范圍內(nèi)使用的一個(gè)friend

  3. 定義該結(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;    ...}...

Handler.h文件中struct Cheshire是一個(gè)不完全的類型說明或者類聲明,具體類定義放在了實(shí)現(xiàn)文件中

Thinking in C++ Chapter 6構(gòu)造函數(shù)相應(yīng)說明
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回跳過構(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ò)誤。

delete void*

當(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}};

Object沒有默認(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ù)

Thinking in C++ Chapter 7overload

使用范圍和參數(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;
}

編譯成功,在C中連接成功,但是在C++中連接出錯(cuò),這是C++中的一種機(jī)制:類型安全連接

Union
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;
}
  1. enum沒有類型名,因?yàn)楹竺鏇]有必要涉及美劇的類型名稱,所以枚舉類型名可選,非必須

  2. union沒有類型名和標(biāo)識(shí)符,稱為匿名聯(lián)合(anonymous union),不需要使用標(biāo)識(shí)符和以點(diǎn)操作符方式訪問這個(gè)union的元素

  3. 訪問一個(gè)匿名聯(lián)合成員就像訪問普通變量一樣,唯一區(qū)別在于:該聯(lián)合的兩個(gè)變量占用同一內(nèi)存空間,如果匿名union在文件作用域內(nèi)(在所有函數(shù)和類之外),則它必須聲明為static,以使它有內(nèi)部的連接

默認(rèn)參數(shù)使用規(guī)則:
  1. 只有參數(shù)列表的后部參數(shù)才可以是默認(rèn)的

  2. 一旦在一個(gè)函數(shù)調(diào)用中開始使用默認(rèn)參數(shù),那么這個(gè)參數(shù)后面的所有參數(shù)都必須為默認(rèn)的

占位符參數(shù)
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指針
  1. const修飾指針正指向的對(duì)象 const int* a;

  2. const修飾在指針中的地址  int* const a;

賦值和類型檢查
  1. const對(duì)象地址不可以賦值給一個(gè)非const指針,但是可以吧一個(gè)非const對(duì)象地址賦值給一個(gè)const指針

  2. 字符數(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}
  1. const指針不可以賦值給非const指針,但是非const指針可以賦值給const指針

  2. 函數(shù)v()返回一個(gè)從字符數(shù)組的字面值中建立的const char *,在編譯器建立了它并把它存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)之后,該聲明實(shí)際上產(chǎn)生該字符數(shù)組的字面值的地址

  3. 函數(shù)w()返回值要求這個(gè)指針以及這個(gè)指針?biāo)赶虻膶?duì)象均為常量,與函數(shù)v()類似,因?yàn)閕是靜態(tài)的,所以函數(shù)返回后返回值仍然有效

  4. const int* const w()只有在作左值時(shí)第二個(gè)const才能顯現(xiàn)作用,所以w()返回值可以賦值給const int *

標(biāo)準(zhǔn)參數(shù)傳遞

可以將臨時(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)行初始化

編譯期間的常量
  1. 一個(gè)內(nèi)建類型的static const可以看成編譯期間的常量,但是該static const必須在定義的地方進(jìn)行初始化

  2. 無標(biāo)記enum也可以看成為編譯期間常量,一個(gè)枚舉在編譯期間必須有值

class X{
  enum {size = 1000};  //same as static const
  static const int size = 1000;  int i[size];
}
const對(duì)象和成員函數(shù)
  1. 若將一個(gè)成員函數(shù)聲明為const,則該成員函數(shù)可以被const對(duì)象調(diào)用

  2. const成員函數(shù)可以調(diào)用非const成員和const成員,非const成員函數(shù)同樣可以使用const成員

  3. const對(duì)象只能調(diào)用const成員函數(shù),非const對(duì)象調(diào)用非const成員函數(shù)

Thinking in C++ Chapter 9內(nèi)聯(lián)函數(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ù)

  1. 內(nèi)聯(lián)函數(shù)體過大時(shí),編譯器將放棄使用內(nèi)聯(lián)

  2. 當(dāng)取函數(shù)地址時(shí),編譯器也將放棄內(nèi)聯(lián)

  3. 一個(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" <<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
  1. 類中包含子對(duì)象,構(gòu)造函數(shù)先調(diào)用子對(duì)象的構(gòu)造函數(shù),如果沒有默認(rèn)構(gòu)造函數(shù),則必須在初始化列表中進(jìn)行初始化,然后在調(diào)用類的構(gòu)造函數(shù)

  2. 類中包含子對(duì)象,先調(diào)用類的析構(gòu)函數(shù)在調(diào)用子類的析構(gòu)函數(shù)

預(yù)處理器
1. #define DEBUG(x) cout << #x "=" << x<<endl;#:字符串化,詳見REF2. #define FIELD(a) char* a##_string;int a##_size##:標(biāo)志粘貼,允許設(shè)兩個(gè)標(biāo)識(shí)符并將它們粘貼在一起產(chǎn)生新的標(biāo)識(shí)符
Thinking in C++ Chapter 10static
  1. 在固定地址上進(jìn)行存儲(chǔ)分配,在一個(gè)特殊的靜態(tài)數(shù)據(jù)區(qū)上創(chuàng)建,不是在堆棧上產(chǎn)生

  2. 對(duì)一個(gè)特定編譯單位來說是局部的,static可以控制名字的可見性,該名字在這個(gè)單元或者類以外是不可見的

static對(duì)象
  1. 如果沒有為一個(gè)內(nèi)建類型的靜態(tài)變量提供一個(gè)初始化值,編譯器會(huì)確保在程序開始時(shí)它被初始化為零(轉(zhuǎn)化成適當(dāng)?shù)念愋?

  2. 如果在定義一個(gè)靜態(tài)對(duì)象時(shí)沒有指定構(gòu)造參數(shù)時(shí),該類必須有默認(rèn)的構(gòu)造函數(shù)

內(nèi)部鏈接

常量、內(nèi)聯(lián)函數(shù)默認(rèn)情況下為內(nèi)部鏈接

others
  1. 所有全局對(duì)象隱含為靜態(tài)存儲(chǔ)

  2. 對(duì)static函數(shù)意味著只在本單元可見,成為文件靜態(tài)(file static)

stactic/const/stctic const
  1. static成員必須在類外初始化,如果不初始化,則編譯器不會(huì)進(jìn)行默認(rèn)初始化,對(duì)于非內(nèi)建類型,可以使用構(gòu)造函數(shù)初始化代替“=”操作符

  2. 類內(nèi)const成員必須在構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化

  3. static const變量(內(nèi)建類型)必須在聲明的地方就初始化

  4. static對(duì)象數(shù)組,包括const和非const數(shù)組必須在類外部初始化

  5. 自定義class類聲明為stctic,不管其為const或者非const都必須在類外初始化

  6. 類的靜態(tài)成員必須進(jìn)行初始化后才可以使用

靜態(tài)成員函數(shù)
  1. 類的靜態(tài)成員函數(shù)不能訪問一般數(shù)據(jù)成員或者函數(shù),只能訪問靜態(tài)數(shù)據(jù)成員,也能調(diào)用其他靜態(tài)成員函數(shù)

  2. 靜態(tài)成員函數(shù)沒有this指針

指針數(shù)組/數(shù)組指針

優(yōu)先級(jí)低的先讀
*p[] 指針數(shù)組
(*p)[] 數(shù)組指針,即指向一個(gè)數(shù)組

函數(shù)指針函數(shù)地址(Function Address)

函數(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)->返回 double
typedef簡化工作量
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
  1. namespace只能在全局范圍內(nèi)定義,但是可以相互嵌套

  2. 在namespace定義的結(jié)尾,右花括號(hào)后面不必跟一個(gè)分號(hào)

  3. 可以按類的語法來定義一個(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();
    //...}
  1. 一個(gè)namespace的名字可以用另一個(gè)名字來作為它的別名
    namespace lib = MyLib;

  2. 不能像類一樣創(chuàng)建一個(gè)名字空間的實(shí)例

未命名的名字空間
namespace {
    class A{};
    class B{};
    int i,j,k;
    //...}

將局部名字放在一個(gè)未命名的名字空間中,不需要加上static就可以作為內(nèi)部連接

using directive& using declaration
using directive:using namespace xxusing declaration:using xx::f;
new/malloc/delete/freenew/malloc

new計(jì)算內(nèi)存大小,并調(diào)用構(gòu)造函數(shù),malloc需要手工計(jì)算內(nèi)存大小,不調(diào)用構(gòu)造函數(shù)

delete/free

delete先執(zhí)行析構(gòu)函數(shù),在清空內(nèi)存,free直接清空內(nèi)存
delete用于void*時(shí)將不會(huì)調(diào)用析構(gòu)函數(shù),直接清空內(nèi)存

重載全局new和delete
  1. 重載的new必須有一個(gè)size_t參數(shù),該參數(shù)由編譯器產(chǎn)生并傳遞給我們,分配內(nèi)存的長度,必須返回一個(gè)指向等于該長度的對(duì)象的指針,如果沒有找到存儲(chǔ)單元,則返回一個(gè)0,然而如果找不到存儲(chǔ)單元,不能僅僅返回0,還應(yīng)該有new-handler或產(chǎn)生一個(gè)異常信息

  2. new返回void*,而不是指向任何特定類型的指針,只需要完成內(nèi)存分配,而不是完成對(duì)象的創(chuàng)建,直到構(gòu)造函數(shù)調(diào)用才能完成對(duì)象的創(chuàng)建,調(diào)用構(gòu)造函數(shù)是編譯器完成的

  3. 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來初始化自身

類重載new和delete

//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*);

為數(shù)組重載new和delete

//p331

定位new/delete

//p333

主要思想:使用new運(yùn)算符重載,但是不對(duì)delete運(yùn)算符重載,指定內(nèi)存位置new
void* operator new(size_t,void*);

繼承與組合(Inheritance&Composition)初始化表達(dá)式
  1. 成員對(duì)象如果沒有默認(rèn)的構(gòu)造函數(shù),必須顯示的進(jìn)行初始化,即在構(gòu)造函數(shù)初始化列表中進(jìn)行初始化

  2. 只有執(zhí)行成員類型初始化之后,才會(huì)進(jìn)入構(gòu)造函數(shù)

  3. 沒有對(duì)所有成員以及基類對(duì)象的構(gòu)造函數(shù)調(diào)用之前,若基類沒有默認(rèn)構(gòu)造函數(shù)則必須初始化,即在初始化列表中進(jìn)行初始化,否則無法進(jìn)入構(gòu)造函數(shù)體

構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用的順序
  1. 構(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ù)

  2. 析構(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ù)

  3. 對(duì)于多重繼承,構(gòu)造函數(shù)調(diào)用順序?yàn)槔^承時(shí)的聲明順序

非自動(dòng)繼承的函數(shù)
  1. 構(gòu)造函數(shù)

  2. 析構(gòu)函數(shù)

  3. operator=

繼承與靜態(tài)成員函數(shù)

靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的共同特點(diǎn):
1. 均可以被繼承到派生類中
2. 重新定義一個(gè)靜態(tài)成員,所有基類中的其他重載函數(shù)會(huì)被隱藏
3. 如果我們改變了基類中的函數(shù)的特征,所有使用該函數(shù)名字的基類版本將會(huì)被隱藏。
4. 靜態(tài)成員函數(shù)不可以是虛函數(shù)

私有繼承
  1. 使用私有繼承是為了不允許該對(duì)象的處理像一個(gè)基類對(duì)象,一般private更適合于組合

  2. 私有繼承成員公有化

class Base{    public:    Base(){}
    ~Base(){}    void name() {cout << "Base name" <<endl;}
}
class Derived:private Base{    public:    Derived(){}
    ~Derived(){}    using Base::name; //私有繼承公有化}
向上類型轉(zhuǎn)換和拷貝構(gòu)造函數(shù)
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)用基類的拷貝構(gòu)造函數(shù)
    ~Derived(){}
}

基類拷貝構(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ù)和返回值說明
  1. 對(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ù)仍然按地址傳遞

  2. 返回值類型取決于運(yùn)算符的具體含義,如果使用該運(yùn)算符產(chǎn)生一個(gè)新值,就需要產(chǎn)生一個(gè)作為返回對(duì)象的新對(duì)象。例如operator+必須生成一個(gè)操作數(shù)之和的對(duì)象,該對(duì)象作為一個(gè)常量通過返回值返回,所以作為一個(gè)左值不會(huì)被改變

  3. 所有賦值運(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ù),這與愿望相違背)

  4. 對(duì)于邏輯運(yùn)算符,人們至少希望得到一個(gè)int返回值,或者最好是bool值

Prefix ++ & Postfix ++
  1. 成員函數(shù)

const Object& operator++(){}const Object operator++(int){}
  1. 友元函數(shù)

const Object& operator++(Object& obj){}const Object operator++(Object& obj,int){}

對(duì)于友元函數(shù)重載來說,因?yàn)閭魅氲腛bject對(duì)象被改變,所以使用非常量引用
 前綴通過引用返回,后綴通過值(臨時(shí)對(duì)象)返回,因?yàn)楹缶Y返回臨時(shí)對(duì)象,所以后綴通過常量值返回,前綴返回引用,如果希望可以繼續(xù)改變對(duì)象則返回引用,否則通過常量引用返回比較合適,這樣與后綴保持了一致性

常量傳值返回與返回值優(yōu)化
  1. 作為常量通常通過傳值方式返回??紤]二元運(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)用

  2. 返回值優(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;

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)化。

operator[]

該運(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<<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; //聲明友元之前必須告知該類存在
    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ù)基本方針
  1. 所有一元運(yùn)算符建議為成員

  2. =()[]->->*必須為成員

  3. += -= /= *= ^= &= |= %= >>= <<=建議為成員

  4. 所有其他二元運(yùn)算符為非成員

copy-on-write

//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è)資訊頻道!

新聞標(biāo)題:ThinkinginC++重點(diǎn)知識(shí)有哪些-創(chuàng)新互聯(lián)
網(wǎng)站鏈接:http://bm7419.com/article22/dihojc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、外貿(mào)建站、網(wǎng)站營銷、關(guān)鍵詞優(yōu)化品牌網(wǎng)站設(shè)計(jì)、建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(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í)需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司