【C++】由Polocar 學習 C++物件導向

shujucn發表於2014-11-19

1、封裝及封裝的意義

封裝可以隱藏實現細節,使得程式碼模組化;封裝是把過程和資料包圍起來,對資料的訪問只能通過已定義的介面。物件導向計算始於這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的物件,這些物件通過一個受保護的介面訪問其他物件。在物件導向程式設計上可理解為:把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏

下面我們就以Polocar這個類開始吧!


class CPoloCar {

    

public:

    

    //C++建構函式,預設的建構函式

    CPoloCar();

    //解構函式

    ~CPoloCar();

    

    //靜態音樂屬性

   static char Music[20];

    //靜態顏色

   static char color[10];

   //車名

   char carName[5];

    //方向盤

   char _fxPan[20];

    //剎車板

   char _brakeBan[20];

    //油門板

   char _oilBan[20];

    

   //轉向

   void zhuanXiang();

   //剎車

   void brake();

   //給油

   void giveOil();

   //導航

   static void navigation();

    //音樂播放

   static void playMusic();

    

private:

    

    //轉向器

    static char _zxqi[20];

    //制動器

   char _zdqi[20];

    

    //轉向助力器

   void zxZlqi();

    //制動執行器

   void dealBrake();

   static void fast();

    

};


2、類 及 類的成員


到這裡我們建立了一個叫做Polocar 的類,其成員包括靜態和非靜態資料成員,靜態與非靜態函式成員。
靜態資料成員:static  char  _zxqi[20]
靜態類中的成員加入static修飾符,即是靜態成員.可以直接使用類名+靜態成員名訪問此靜態成員,因為靜態成員存在於記憶體,非靜態成員需要例項化才會分配記憶體,所以靜態成員不能訪問非靜態的成員..因為靜態成員存在於記憶體,所以非靜態成員可以直接訪問類中靜態的成員
靜態函式成員:static  void fast()
所有沒有加Static的成員都是非靜態成員,當類被例項化之後,可以通過例項化的類名進行訪問..非靜態成員的生存期決定於該類的生存期..而靜態成員則不存在生存期的概念,因為靜態成員始終駐留在內容中.. 

3、在程式導向設計中的static關鍵字 
1)、靜態全域性變數 
定義:在全域性變數前,加上關鍵字 static 該變數就被定義成為了一個靜態全域性變數。 
特點: 
  A、該變數在全域性資料區分配記憶體。 
  B、初始化:如果不顯式初始化,那麼將被隱式初始化為0(自動變數是隨機的,除非顯式地初始化)。 
  C、訪變數只在本原始檔可見,嚴格的講應該為定義之處開始到本檔案結束。
      D、檔案作用域下宣告的const的常量預設為static儲存型別。 
  例(摘於C++程式設計教程---錢能主編P103):         //file1.cpp 
//Example 1

#include <iostream.h>

void fn();

static int n;//定義靜態全域性變數

void main()

{

   n=20;

    cout < <n < <endl;

   fn();

}


void fn()

{

   n++;

    cout < <n < <endl;

}

 
靜態變數都在全域性資料區分配記憶體,包括後面將要提到的靜態區域性變數。對於一個完整的程式,在記憶體中的分佈情況如下圖: 
程式碼區
全域性資料區
堆區
棧區
              


void main()

{

    n=20;

    cout < <n < <endl;

    fn();

}


//File2

#include <iostream.h>

extern int n;(可在別的檔案中引用這個變數)

void fn()

{

    n++;

    cout < <n < <endl;

}


編譯並執行Example 2,您就會發現上述程式碼可以分別通過編譯,但link時出現錯誤。

試著將 static int n; //定義靜態全域性變數 
改為 
int n; //定義全域性變數 

再次編譯執行程式,細心體會全域性變數和靜態全域性變數的區別。

2)、靜態區域性變數 
定義:在區域性變數前加上static關鍵字時,就定義了靜態區域性變數。我們先舉一個靜態區域性變數的例子,

//Example 3

#include <iostream.h>

void fn();

void main()

{

    fn();

    fn();

    fn();

}

void fn()

{

    static n=10;

    cout < <n < <endl;

    n++; 

}

  通常,在函式體內定義了一個變數,每當程式執行到該語句時都會給該區域性變數分配棧記憶體。但隨著程式退出函式體,系統就會收回棧記憶體,區域性變數也相應失效。 
  但有時候我們需要在兩次呼叫之間對變數的值進行儲存。通常的想法是定義一個全域性變數來實現。但這樣一來,變數已經不再屬於函式本身了,不再僅受函式的控制,給程式的維護帶來不便。 
  靜態區域性變數正好可以解決這個問題。靜態區域性變數儲存在全域性資料區,而不是儲存在棧中,每次的值保持到下一次呼叫,直到下次賦新值。 

特點: 
  A、該變數在全域性資料區分配記憶體。 
  B、初始化:如果不顯式初始化,那麼將被隱式初始化為0,以後的函式呼叫不再進行初始化。 
  C、它始終駐留在全域性資料區,直到程式執行結束。但其作用域為區域性作用域,當定義它的函式或 語句塊結束時,其作用域隨            之結束。

3)、靜態函式(注意與類的靜態成員函式區別)
 定義:在函式的返回型別前加上static關鍵字,函式即被定義成靜態函式。 
特點:   
A、靜態函式與普通函式不同,它只能在宣告它的檔案當中可見,不能被其它檔案使用。   
定義靜態函式的好處:靜態函式不能被其它檔案所用; 
其它檔案中可以定義相同名字的函式,不會發生衝突;
 
4、物件導向的static關鍵字(類中的static關鍵字) 

1)、靜態資料成員 
在類內資料成員的宣告前加上關鍵字static,該資料成員就是類內的靜態資料成員。
先舉一個靜態資料成員的例子。 

CPoloCar::CPoloCar()

{

    cout << "方向盤初始化"<< endl;

    strcpy(_fxPan,"方向盤初始化");

}


CPoloCar::~CPoloCar()

{

    cout << "銷燬這輛車"<< endl;

}


void CPoloCar::zhuanXiang()

{

    cout << "轉向" << endl;

}


void CPoloCar::brake()

{

    cout << "制動"<<endl;

    dealBrake();

}


void  CPoloCar::giveOil()

{

    cout <<"給油"<<endl;

}


void CPoloCar::dealBrake()

{

    cout << "真正執行制動的裝置" <<endl;

}


void CPoloCar::zxZlqi()

{

    cout << "實現轉向" << endl;

}


void CPoloCar::navigation()

{

    cout << "Navigation"<< endl ;

}


void CPoloCar::playMusic(){

    cout<< "Playing music " << Music[20]<<endl ;

}


可以看出,靜態資料成員有以下特點: 
靜態資料成員初始化與一般資料成員初始化不同。

靜態資料成員初始化的格式為: 
<資料型別><類名>::<靜態資料成員名>=<值> 

類的靜態資料成員有兩種訪問形式: 
<類物件名>.<靜態資料成員名> 或 <類型別名>::<靜態資料成員名> 

對於非靜態資料成員,每個類物件都有自己的拷貝。而靜態資料成員被當作是類的成員。無論這個類的物件被定義了多少個,靜態資料成員在程式中也只有一份拷貝,由該型別的所有物件共享訪問。也就是說,靜態資料成員是該類的所有物件所共有的。對該類的多個物件來說,靜態資料成員只分配一次記憶體,供所有物件共用。所以,靜態資料成員的值對每個物件都是一樣的,它的值可以更新; 
靜態資料成員儲存在全域性資料區。靜態資料成員定義時要分配空間,所以不能在類宣告中定義。在Example 5中,語句int Myclass::Sum=0;是定義靜態資料成員; 
靜態資料成員和普通資料成員一樣遵從public,protected,private訪問規則; 
因為靜態資料成員在全域性資料區分配記憶體,屬於本類的所有物件共享,所以,它不屬於特定的類物件,在沒有產生類物件時其作用域就可見,即在沒有產生類的例項時,我們就可以操作它; 

如果靜態資料成員的訪問許可權允許的話(即public的成員),可在程式中,按上述格式來引用靜態資料成員 ; 
靜態資料成員主要用在各個物件都有相同的某項屬性的時候。比如對於一個存款類,每個例項的利息都是相同的。所以,應該把利息設為存款類的靜態資料成員。
這有兩個好處,第一,不管定義多少個存款類物件,利息資料成員都共享分配在全域性資料區的記憶體,所以節省儲存空間。
第二,一旦利息需要改變時,只要改變一次,則所有存款類物件的利息全改變過來了;
同全域性變數相比,使用靜態資料成員有兩個優勢:
 
靜態資料成員沒有進入程式的全域性名字空間,因此不存在與程式中其它全域性名字衝突的可能性; 
可以實現資訊隱藏。靜態資料成員可以是private成員,而全域性變數不能; 

2、靜態成員函式 

  與靜態資料成員一樣,我們也可以建立一個靜態成員函式,它為類的全部服務而不是為某一個類的具體物件服務。靜態成員函式與靜態資料成員一樣,都是類的內部實現,屬於類定義的一部分。普通的成員函式一般都隱含了一個this指標,this指標指向類的物件本身,因為普通成員函式總是具體的屬於某個類的具體物件的。通常情況下,this是預設的。如函式fn()實際上是this->fn()。
但是與普通函式相比,靜態成員函式由於不是與任何的物件相聯絡,因此它不具有this指標。從這個意義上講,它無法訪問屬於類物件的非靜態資料成員,也無法訪問非靜態成員函式,它只能呼叫其餘的靜態成員函式。
下面舉個靜態成員函式的例子。 

//Example 6 
#include <iostream.h> 
class Myclass 

public: 
Myclass(int a,int b,int c); 
static void GetSum();/宣告靜態成員函式 
private: 
int a,b,c; 
static int Sum;//宣告靜態資料成員 
}; 
int Myclass::Sum=0;//定義並初始化靜態資料成員 

Myclass::Myclass(int a,int b,int c) 

this->a=a; 
this->b=b; 
this->c=c; 
Sum+=a+b+c; //非靜態成員函式可以訪問靜態資料成員 


void Myclass::GetSum() //靜態成員函式的實現 

// cout < <a < <endl; //錯誤程式碼,a是非靜態資料成員 靜態成員函式由於不是與任何的物件相聯絡,因此它不具有this指標。從這個意義上講,它無法訪問屬於類物件的非靜態資料成員,也無法訪問非靜態成員函式,它只能呼叫其餘的靜態成員函式。
cout < <"Sum=" < <Sum < <endl; 


void main() 

Myclass M(1,2,3); 
M.GetSum(); 
Myclass N(4,5,6); 
N.GetSum(); 
Myclass::GetSum(); 


關於靜態成員函式,可以總結為以下幾點: 


出現在類體外的函式定義不能指定關鍵字static; 
靜態成員之間可以相互訪問,包括靜態成員函式訪問靜態資料成員和訪問靜態成員函式; 
非靜態成員函式可以任意地訪問靜態成員函式和靜態資料成員; 
靜態成員函式不能訪問非靜態成員函式和非靜態資料成員; 
由於沒有this指標的額外開銷,因此靜態成員函式與類的全域性函式相比速度上會有少許的增長; 
呼叫靜態成員函式,可以用成員訪問操作符(.)和(->)為一個類的物件或指向類物件的指標呼叫靜態成員函式.








相關文章