1. 程式人生 > >C++ 物件和例項的區別,以及用new和不用new建立類物件區別

C++ 物件和例項的區別,以及用new和不用new建立類物件區別

起初剛學C++時,很不習慣用new,後來看老外的程式,發現幾乎都是使用new,想一想區別也不是太大,但是在大一點的專案設計中,有時候不使用new的確會帶來很多問題。當然這都是跟new的用法有關的。new建立類物件,使用完後需使用delete刪除,跟申請記憶體類似。所以,new有時候又不太適合,比如在頻繁呼叫場合,使用區域性new類物件就不是個好選擇,使用全域性類物件或一個經過初始化的全域性類指標似乎更加高效。

C++ 物件例項化的一些概念 C++ 如果直接定義類,如classA  a; a存在棧上(也意味著複製了物件a在棧中);
如果classA  a = new classA就存在堆中。

一、new建立類物件與不new區別

下面是自己總結的一些關於new建立類物件特點:

  • new建立類物件需要指標接收,一處初始化,多處使用
  • new建立類物件使用完需delete銷燬
  • new建立物件直接使用堆空間,而區域性不用new定義類物件則使用棧空間
  • new物件指標用途廣泛,比如作為函式返回值、函式引數等
  • 頻繁呼叫場合並不適合new,就像new申請和釋放記憶體一樣

二、new建立類物件例項

1、new建立類物件例子:

CTest* pTest = new CTest();

delete pTest;

pTest用來接收類物件指標。

不用new,直接使用類定義申明:

CTest mTest;

此種建立方式,使用完後不需要手動釋放,該類解構函式會自動執行。而new申請的物件,則只有呼叫到delete時再會執行解構函式,如果程式退出而沒有執行delete則會造成記憶體洩漏。

2、只定義類指標

這跟不用new申明物件有很大區別,類指標可以先行定義,但類指標只是個通用指標,在new之前併為該類物件分配任何記憶體空間。比如:

CTest* pTest = NULL;

但使用普通方式建立的類物件,在建立之初就已經分配了記憶體空間。而類指標,如果未經過物件初始化,則不需要delete釋放

3、new物件指標作為函式引數和返回值

下面是天緣隨手寫一個例子,不太嚴謹。主要示意一下類指標物件作為返回值和引數使用。

  1. class CTest {  public:   int a;  };      
  2. class CBest {  public:   int b;  };      
  3. CTest* fun(CBest* pBest) {    
  4.                            CTest* pTest = new CTest();     
  5.                            pTest->a = pBest->b;   return pTest;    
  6. }      
  7. int main() {    
  8.              CBest* pBest = new CBest();     
  9.              CTest* pRes= fun(pBest);        
  10.              if(pBest!=NULL)      
  11.              delete pBest;     
  12.              if(pRes!=NULL)      
  13.              delete pRes ;     
  14.              return 0;    
  15. }  

C++物件例項化

  1. JAVA:  
  2. A a = new A();  
  3. 為A物件建立了一個例項,但在記憶體中開闢了兩塊空間:一塊空間在堆區,存放new A()這個物件;  
  4. 另一塊空間在堆疊,也就是棧,存放a,a的值為new A()這個物件的記憶體地址。因為java在JVM中執行,  
  5. 所以a 描述的記憶體地址不一定是這個物件真實記憶體的地址。  
  6. Object o; // 這是宣告一個引用,它的型別是Object,他的值為null,還沒有指向任何物件,該引用放在記憶體的棧區域中。
  7. o = new Object(); // new Object()句,例項化了一個物件,就是在堆中申請了一塊連續空間用來存放該物件。
  8. // 運算子,將引向o指向了物件。也就是說將棧中表示引用o的記憶體地址的內容改寫成了Object物件在堆中的地址。
  9. C++:  
  10. C++ 如果直接定義類,如classA a; a 存在棧上(也意味著複製了物件a在棧中),如果classA a = new classA就存在堆中。  

初學Java時,在很長一段時間裡,總覺得基本概念很模糊。後來才知道,在許多Java書中,把物件和物件的引用(例項)混為一談

如果分不清物件與物件引用,那實在沒法很好地理解下面的面向物件技術,把自己的一點認識寫下來,或許能讓初學Java的朋友們少走一點彎路。

為便於說明,我們先定義一個簡單的類:
  1. class student  
  2. {  
  3.       int name;  
  4.       int age;  
  5.       int sex;  
  6. }  

有了這個類(模板),就可以用它來建立物件:student stu1 = new  student();

通常把這條語句的動作稱之為建立一個物件,其實,它包含了四個動作

1)右邊的"new  student",是以student類為模板,在堆空間裡建立一個student類的物件(也簡稱為student物件)

2)末尾的()意味著,在物件建立後,立即呼叫student類的建構函式,對剛生成的物件進行初始化

    建構函式是肯定有的。如果你沒寫,Java會給你補上一個預設的建構函式。

3)左邊的"student stu1"建立了一個student類引用變數。所謂student類引用,就是以後可以用來指向某個 

    student物件的物件引用,它指向的是某個student物件的記憶體地址(有點C語言中指標的味道)

4)"="操作符使物件引用指向剛建立的那個student物件

我們可以把這條語句拆成兩部分student  stu1;                 (1)

                                                             stu1 = new student();     (2)

    效果是一樣的

    這樣寫,就比較清楚了,有兩個實體:一是物件引用變數(stu1),在Sun公司的實現中,物件的引用是一個控制代碼,其中包含一對指標:一個指標指向該物件的方法表,一個指向該物件的資料另一個是物件本身(就是new出來的那個物件)

    在堆空間裡建立的實體,與在資料段以及棧空間裡建立的實體不同。儘管它們也是確確實實存在的實體,但是,我們看不見,也摸不著。不僅如此,我們仔細研究一下第二句,想想剛剛建立的student物件叫什麼名字?

    有人說,它叫"student"。不對,"student"是類(物件的建立模板)的名字。一個student類可以據此建立出無數個物件,這些物件不可能全叫"student"物件連名都沒有,沒法直接訪問它。我們只能通過物件引用(例項)來間接訪問物件

為了形象地說明物件、物件引用及它們之間的關係,可以做一個或許不很妥當的比喻:

    物件好比是一隻沒有線的風箏,引用變數是一根線,可以用來系風箏。如果只執行了第一條語句還沒執行第二條,此時建立的引用變數stu1還沒指向任何一個物件,它的值是null,引用變數可以指向某個物件,或者為null。這時stu1是一根線,一根還沒有繫上任何一個風箏的線。

   執行了第二句後,一隻新風箏做出來了,並被系在stu1這根線上。我們抓住這根線,就等於抓住了那隻風箏。

   再來一句:student  stu2;就又做了一根線,還沒繫上風箏。如果再加一句:stu2=stu1;繫上風箏了

   這裡,發生了複製行為。但是,要說明的是,物件本身並沒有被複制,被複制的只是物件引用

   結果是,stu2也指向了stu1所指向的物件,也就是兩根線系的是同一只風箏。

   如果用下句再建立一個物件:stu2=newstudent();則引用變數stu2改指向第二個物件。

   從以上敘述再推演下去,我們可以獲得以下結論:

   (1)一個物件引用可以指向0個或1個物件(一根線可以不繫風箏,也可以系一個風箏),而且可以改指;

   (2)一個物件可以有N個引用指向它(可以有N條線系同一個風箏)

    如果有下面語句:stu1=stu2;

按上面的推斷,stu1也指向了第二個物件。這個沒問題。問題是第一個物件呢?沒有一條線繫住它,它飛了。

    很多書裡說,它被Java的垃圾回收機制回收了,這不確切,準確地說,它已成為Java垃圾回收機制的處理物件。至於什麼時候真正被回收,那要看垃圾回收機制的心情了。由此看來,new  student();該語句應該不合法吧,至少是沒用的吧?不對,它是合法的,而且可用的。譬如,如果我們僅僅為了列印而生成一個物件,就不需要用引用變數來繫住它。最常見的就是列印字串:System.out.println("Iam Java!");

    字串物件"I amJava!"在列印後即被丟棄,有人把這種物件稱之為臨時物件。

最後再說明一下:

C++中:

Student  student(20) ;  //這裡student是引用 物件分配在 棧空間中,這裡只是我的理解

Student *student = new  Student(20);  //這裡student是指標,new Student(20)是分配在堆記憶體空間的

但是在Java中

Student  student(20) ;  //注意:java中沒有這樣例項化物件的, 要想得到一個物件 必須要new出來.

Student student ; //這個只是定義了一個引用 ,沒有指向任何物件

Student student = new Student(20);   //定義了一個引用,指向堆記憶體中的student物件