1. 程式人生 > 其它 >八、this指標、靜態成員、成員物件和封閉類

八、this指標、靜態成員、成員物件和封閉類

1、this指標

1)this指標的作用

其作用就是指向成員函式所作用 的物件

非靜態成員函式中可以直接使用this來代表指向該函式作用的物件的指標。

2)this指標和靜態成員函式

靜態成員函式中不能使用 this 指標!

因為靜態成員函式並不具體作用與某個物件!

因此,靜態成員函式的真實的引數的個數,就是程 序中寫出的引數個數!

非靜態成員函式的引數個數=所寫引數個數+1;

2、靜態成員

1)基本概念

     靜態成員:在說明前面加了static關鍵字的成員。

例如:

class CRectangle
{
private:
int w, h;
static int nTotalArea; //
靜態成員變數 static int nTotalNumber; public: CRectangle(int w_,int h_); ~CRectangle(); static void PrintTotal(); //靜態成員函式 };

    普通成員變數每個物件有各自的一份,而靜態成員變數一共就一份,為所有物件共享。

注意:sizeof 運算子不會計算靜態成員變數。

    普通成員函式必須具體作用於某個物件,而靜態成員 函式並不具體作用於某個物件。

    因此靜態成員不需要通過物件就能訪問。

    靜態成員變數本質上是全域性變數,哪怕一個物件都不存在,類 的靜態成員變數也存在。

    靜態成員函式本質上是全域性函式。

       設定靜態成員這種機制的目的是將和某些類緊密相關的全域性變 量和函式寫到類裡面,看上去像一個整體,易於維護和理解。

2)如何訪問靜態成員

方法1:類名::成員名

方法2:物件名.成員名

方法3:指標->成員名

方法4:引用名.成員名

3)靜態成員示例

考慮一個需要隨時知道矩形總數和總面積的圖形處理程式,可以用全域性變數來記錄總數和總面積

用靜態成員將這兩個變數封裝進類中,就更容易 理解和維護

class CRectangle
{
 private:
  int w, h;
  static int nTotalArea;
  static int nTotalNumber;
public:   CRectangle(int w_,int h_);   ~CRectangle();   static void PrintTotal(); }; CRectangle::CRectangle(int w_,int h_) {   w = w_;   h = h_;   nTotalNumber ++;   nTotalArea += w * h; } CRectangle::~CRectangle() {   nTotalNumber --;   nTotalArea -= w * h; } void CRectangle::PrintTotal() {   cout << nTotalNumber << "," << nTotalArea << endl; } int CRectangle::nTotalNumber = 0; int CRectangle::nTotalArea = 0; // 必須在定義類的檔案中對靜態成員變數進行一次說明 //或初始化。否則編譯能通過,連結不能通過。 int main() {   CRectangle r1(3,3), r2(2,2);   //cout << CRectangle::nTotalNumber; // Wrong , 私有   CRectangle::PrintTotal();   r1.PrintTotal();   return 0; }
輸出結果:
2,13
2,13

4)注意事項

  • 在靜態成員函式中,不能訪問非靜態成員變數, 也不能呼叫非靜態成員函式。
  • 在使用CRectangle類時,有時會呼叫複製建構函式 生成臨時的隱藏的CRectangle物件

    用一個以CRectangle類物件作為引數的函式時, 呼叫一個以CRectangle類物件作為返回值的函式時

臨時物件在消亡時會呼叫解構函式,減少nTotalNumber 和 nTotalArea的值,可是這些臨時物件在生成時卻沒有增加 nTotalNumber 和 nTotalArea的值。

解決辦法:為CRectangle類寫一個複製建構函式。

CRectangle :: CRectangle(CRectangle & r )

{ w = r.w; h = r.h; nTotalNumber ++; nTotalArea += w * h; }

 3、成員物件和封閉類

1)基本概念

成員物件:當一個類的成員是另一個類的物件時,這個物件就叫成員物件。概括的說,就是一個類的成員是一個物件,即成員物件。

有成員物件的類叫封閉(enclosing)類。

class CTyre //輪胎類
{
private:
    int radius; //半徑
    int width; //寬度
public:
    CTyre(int r,int w):radius(r),width(w) { }
};

class CEngine //引擎類
{
};
 
class CCar { //汽車類
private:
    int price; //價格
    CTyre tyre;
    CEngine engine;
public:
    CCar(int p,int tr,int tw );
};

CCar::CCar(int p,int tr,int w):price(p),tyre(tr, w)
{
};

int main()
{
    CCar car(20000,17,225); 
    return 0;
}

上例中,如果 CCar類不定義建構函式, 則下面的語句會編譯出錯:

   CCar car;

因為編譯器不明白 car.tyre該如何初始化。car.engine 的初始化沒問題,用預設建構函式即可。

任何生成封閉類物件的語句,都要讓編譯器明白,物件中的成員物件,是如何初始化的。

具體的做法就是:通過封閉類的建構函式的初始化列表。

成員物件初始化列表中的引數可以是任意複雜的表示式,可以包括函式,變數 ,只要表示式中的函式或變數有定義就行。

2)封閉類建構函式和解構函式的執行順序

  封閉類物件生成時,先執行所有物件成員的建構函式,然後才執行封閉類的建構函式。

  物件成員的建構函式呼叫次序和物件成員在類中的說明次序一致 ,與它們在成員初始化列表中出現的次序無關。

  當封閉類的物件消亡時,先執行封閉類的解構函式,然後再執行成員物件的解構函式。次序和建構函式的呼叫次序相反。

class CTyre {
public:
    CTyre() { cout << "CTyre contructor" << endl; }
    ~CTyre() { cout << "CTyre destructor" << endl; }
};

class CEngine {
public:
    CEngine() { cout << "CEngine contructor" << endl; }
    ~CEngine() { cout << "CEngine destructor" << endl; }
};

class CCar {
private:
    CEngine engine; 
    CTyre tyre;
public:
    CCar( ) { cout << “CCar contructor” << endl; }
    ~CCar() { cout << "CCar destructor" << endl; }
};
 
int main(){
    CCar car; 
    return 0;
}
輸出結果:
CEngine contructor
CTyre contructor
CCar contructor
CCar destructor
CTyre destructor
CEngine destructor

3)封閉類的複製建構函式

封閉類的物件,如果是用預設複製建構函式初始化的,那麼它裡面包含的成員物件, 也會用複製建構函式初始化。

class A
{
public:
    A() { cout << "default" << endl; }
    A(A & a) { cout << "copy" << endl;}
};
class B {
    A a; 
};
int main()
{
    B b1,b2(b1);
    return 0;
}