天天看點

C++程式設計思想學習筆記-命名控制

C++程式設計思想學習筆記-命名控制

一、           static的使用

1、  對于全局變量(即main函數之外的變量):static表示内部連接配接,無staic則為外部連接配接,而用extern可以使用其他編譯單元中的外部連接配接變量。另外全局變量始終存儲在靜态存儲區。全局靜态對象的構造函數是在main()之前執行的,而析構函數是在main()之後執行的,是以利用這點可以在main()函數之前之後執行代碼。一般頭檔案中的變量應控制為内部連接配接,這樣兩個同時都包含此頭檔案的編譯單元在連接配接時就不會有名字沖突了。

2、  對于局部變量(配置設定于堆棧的變量):static使變量被配置設定到靜态存儲區,預設初始化一次且第一次(内部資料類型為0,使用者自定義調用構造函數),生命期同全局變量(從定義到程式結束),但隻在該函數内部可見。靜态對象的析構函數在main函數退出時調用,多數是随着exit()函數的調用而被調用,是以不要在析構函數中調用exit()函數,以防死循環。但若用c庫函數abort()結束程式則析構函數不會被調用。靜态對象的銷毀是按它們初始化的相反順序進行的,且未被調用函數中的靜态對象不會被建立,是以也不會被銷毀。

3、  對于類中的成員:static使類的靜态成員擁有一個單獨的靜态存儲區,這一存儲區屬于該類,該類的對象共享這塊存儲區,共享這些靜态成員,這樣就提供了一種讓對象之間通信的方法。靜态成員屬于類,位址是定的;而非靜态成員屬于對象,位址是動态配置設定的;是以靜态成員隻能調用靜态成員,不能調用非靜态成員;而非靜态成員則可以都通路,但對靜态成員的通路會影響類的資料及其他的對象。

×靜态資料成員隻能在類的外部定義且隻能定義一次,一般放在類的實作檔案中;

 注意:在定義靜态數組時不能自動計數,必須指明數組大小。另外static const int可以做為類中的編譯時常量。在嵌套類中可以定義靜态成員,但在局部類中不能。

×靜态成員函數隻能通路靜态資料成員和靜态成員函數,這有一個應用,可以定義一個隻能有一個對象的類,首先構造函數必須為私有(保證不能構造其他執行個體),但如何初始化呢?是以這個對象必須是類中的靜态資料成員(保證可以用靜态成員的定義方法來初始化),示例如下:

              #include<iostream.h>

Class egg{

           static egg E;//為什麼要私有?

           int i;//此資料屬于對象,必須用對象通路

           egg(int I):i(I){}//構造函數私有,隻能内部通路。

public:

           static egg* instance(){return &E;}//獲得對象的位址

           int val(){return i;}

};

egg egg::E(47);

main(){

           //! egg x(1); //不能建立對象;

           cout<<egg::instance()->val()<<endl;

}

4、  靜态初始化的依賴(extern的使用):看如下示例:

×示例1

//first file

#include<fstream.h>

ostream out(“out.txt”);

第二個檔案

//second file

#include<fstream.h>

extern ofstream out;

class oof{

public:

        oof(){out<<”barf”;}

}OOF;

這個示例程式可能運作,也可能不運作,若建立可執行檔案時第一個檔案先初始化則沒問題,但若第二個檔案先初始化,則會引起混亂。

×示例2(ARM中)

第一個檔案

extern int y;

int x=y+1;

第二個檔案

extern int x;

int y=x+1;

對于這個示例,若第一個檔案先初始化則y=0,x=1,y=2;若第二個檔案先初始化則x=0,y=1,x=2;這兩種結果相差很大。

×解決方法:

(1)不用它;(2)關鍵的靜态對象的定義放到一個檔案中;

(3)在庫頭檔案中增加一個額外的類控制庫中靜态對象的動态初始化,示例如下:

#ifdef DEFEND_H_

#define DEFEND_H_

#include <iostream>

extern int x;//Declarations,not definitions

extern int y;

class initializer

{         

static int init_conut;

public:

               initializer()

               {

                  cout<<"initializer()"<<endl;

                  //Initialize first time only

                  if(init_conut++==0)

                     {

                         cout<<"performing initialization"<<endl;

                         x=100;

                          y=200;

                     }

               }

               ~initializer()

               {

                  cout<<"~initializer()"<<endl;

                  //Clean up last time only

                  if(--init_conut==0)

                     {

                         cout<<"performing cleanup"<<endl;

                         //Any necessary cleanup here

                     }

               }

protected:

private:

};

//the following creates one object in each

//file where DEFEND.H is included,but that

//object is only visible within that file:

static initializer init;

#endif

實作檔案如下:

           #include "depend.h"

//static initialization will force

//all these values to zero;

int x;

int y;

int initializer::init_conut;

此種情況是在你的庫中有extern對象,會引起初始化依賴問題,通過一個類中的靜态計數變量來來記錄初始化,若是第一次包含頭檔案則初始化,否則不用再初始化,對于其他的頭檔案包含則會跳過初始化;即保證任何情況都會初始化且隻一次。

        (extern “C”{ func1(a,b);func2(a,b);}的使用方法);

二、namespace的使用

    1、namespace隻能在全局範疇定義,但可以嵌套;

    2、namespace可以在多個頭檔案中用同一個辨別符來定義;

    3、一個namespace可以用另外一個名字做為别名:namespace a=abcdef;

    4、未命名的namespace表示全部是内部連接配接;

5、可以在namespace中插入friend聲明,則被聲明的友元也成為此namespace

中的一員;

    6、using namespace a;

       using namespace b;

       當a和b中存在相同的名字時,在使用時會産生沖突;

       而利用using聲明可以覆寫掉using指令中的名字;

       using指令是省去了每次輸入名字空間修飾的麻煩,而using聲明是把名

       字空間中的成員再次聲明一下;舉例如下:

       namespace U{

           void f();

           void g();

}

namespace V{

           void f();

           void g();

}

對于using namespace U;f();等同于U::f();此時f為全局名,可被局部名覆寫;

對于using U::f;f();等同于void f();f();//U中f的再次聲明

此時f為局部名;效果如下面代碼:

void func(){

           using namespace U;//Using directive

           using V::f;//Using declaration

           f();//calls V::f()

           U::f();//must fully qualify to call

}