2012-07-21 34 views
1

我正在閱讀一本C++書,我對指向類有些困惑。C++指向類

在本書前面的例子中使用的類和方法是這樣的:

Calculator myCalc; 
myCalc.launch(); 

while(myCalc.run()){ 
    myCalc.readInput(); 
    myCalc.writeOutput(); 
} 

然而,現在它改成做這種方式:

Calculator* myCalc = new Calculator; 
myCalc -> launch(); 

while(myCalc -> run()){ 
    myCalc -> readInput(); 
    myCalc -> writeOutput(); 
} 

而且我似乎無法到在那裏找到一個解釋,爲什麼它這樣做。

爲什麼我要以這種方式指向一個類,而不是使用標準的方式來做到這一點?

有什麼區別?哪種情況會更好?

謝謝。

+0

這本書是否「刪除」它? – chris 2012-07-21 14:30:47

+3

術語有點不合適。您不指向類,指向對象或類的實例。 – juanchopanza 2012-07-21 14:33:15

+0

@chris不如我所見。這只是一個非常簡短的例子,它沒有詳細描述。 – 2012-07-21 14:48:30

回答

7

首先,您不是指向該類,而是指向類的實例,也稱爲對象。 (指向類不可能在C++中,如果你問我,它的缺點之一)。

區別在於分配對象的地方。當你在做:

Calculator myCalc; 

整個對象創建在stack。該堆棧是本地變量,嵌套調用等的存儲區,通常限制爲1 MB或更低。另一方面,堆棧上的分配速度更快,因爲不涉及內存管理器調用。

當你這樣做:

Calculator *myCalc; 

沒有太多的情況,不同的是Pointer是在棧上分配。指針的大小通常爲4或8個字節(32位與64位體系結構),並且只保存一個存儲器地址。你必須分配一個對象,並通過執行類似使指針指向它:

myCalc = new Calculator; 

一樣顯示在您的例子,也可以組合成一條線。在這裏,該對象被分配在heap上,該對象大約與您的物種內存大小相同(不考慮交換空間和架構限制),因此您可以在那裏存儲更多數據。但速度較慢,因爲內存管理器需要爲堆棧找到堆中的備用空間,甚至需要從操作系統獲取更多內存。現在指針myCalc包含對象的內存地址,因此它可以與*->運算符一起使用。

此外,您不能將指針或引用指向堆棧以外的對象,因爲在作用域結束時(即在函數結束時),堆棧將得到清理,從而導致對象不可用。

哦,差點忘了提。在堆對象不會自動銷燬,所以你必須手動刪除它們像這樣*:

delete myCalc; 

所以總結一下:對於那些不離開其範圍小,短壽命的對象,你可以使用基於堆棧的分配,而對於更大,更長的活動對象,堆通常是更好的地方。


*:那麼,理想情況下,不是那樣的。使用智能指針,如std::unique_ptr

+0

指針也可以是16個字節,128個字節。 – Linuxios 2012-07-21 14:35:36

+0

@Linuxios不在當前的體系結構上;),但我會添加一個「通常」。 – 2012-07-21 14:37:19

+3

@Linuxios:如果奶奶有鋼絲,我們也許可以稱她爲雨傘。讓我們在這裏實用,而不是通過使討論太籠統,恕我直言,增加了混亂。 – 2012-07-21 14:38:08

1

兩者都是標準配置。一個不比另一個更受歡迎。

第一個是典型的局部變量,你聲明和使用在一個狹窄的範圍內。

指針方法允許您動態分配內存並將其分配給指針類型;這就是「明星」符號的含義。這些可以傳出一個方法或分配給一個成員變量,在一個方法退出後生活。

但是你必須意識到,當你完成指針指向的對象時,你也負責清理那些內存。如果你不這樣做,你最終會耗盡長時間運行的應用程序,造成「內存泄漏」。

1

當你使用 - >如果你的變量是一個指向類的實例的指針時,你的變量是類的實例或引用時使用點(。)。

1

它們都是C++標準的一部分,但有一個核心的區別。在第一種方式中,你的對象位於堆棧上(這是函數和局部變量的存儲位置,並且在不再使用它們之後被移除)。當你將變量類型聲明爲一個指針時,你只是在棧上存儲一個指針,並且該對象本身正在堆上。

雖然當您使用堆棧局部變量來分配內存時,它將由C++自動處理。當它在堆上時,必須使用new獲取內存並使用delete釋放它。

儘管在堆棧的例子代碼使用.來調用方法,調用上的指針的方法,C++提供了一條捷徑:->,這相當於*obj.method()

請記住,當您使用new時,總是use delete

0

一個用途是如果變量myCalc的壽命很長。您可以在需要時使用new創建它,並在使用delete完成時將其刪除。那麼你不必擔心在不需要的時候攜帶它並且只佔用空間。或者你可以在需要時隨意重新初始化等。

或者當你有一個非常大的班級時,通常使用new來將它分配給堆而不是堆棧。這是堆棧空間稀少和堆棧較大時的剩餘,因此堆空間更便宜。

或者,當然,最常見的用法是分配一個動態數組。 myCalc = new Calculator[x];創建x新計算器。如果事先不知道多大的話,你不能用靜態變量來做到這一點;你打算創建多少個對象。

0

除了符號/語法的明顯區別之外。將數據傳遞給函數時,指針通常很有用。

void myFunc(Calculator *c) { 
    ... 
} 

通常優於

void myFunc(Calculator c) { 
    ... 
} 

由於第二需要副本進行的計算器。一個指針只包含指向內容的位置,所以它只能引用內存中的另一個位置,而不是包含數據本身。另一個好的用途是用於字符串,想象一下讀取一個文本文件並調用函數來處理文本,如果它不是指針,則每個函數都會創建一個字符串的副本。一個指針可以是4或8個字節,具體取決於機器的體系結構,因此當傳遞給函數時可以節省大量的時間和內存。

在某些情況下,儘管使用副本可能會更好。也許你只是想返回一個修改過的版本,像這樣

Calculator myFunc(Calculator c) { 
    ... 
} 

約指針重要的事情之一是「新」的關鍵字。這不是創建指針的唯一方法,但它是C++的最簡單方法。你也應該可以使用一個叫做malloc()的函數,但是對於structs和c IMO來說更多,但是我已經看到了兩種方法。

說到C.指針也可能適用於數組。我認爲你仍然只能在編譯時用C++聲明數組的大小,但我可能會誤解。你可以使用下面我相信

Calculator *c; 
.... 
Calculator d = c[index]; 

所以,現在你有一個數組它可以使相當曖昧IMO。

我認爲這涵蓋了我所知道的全部內容,並且在提供的示例中,我認爲您提供的兩個片段之間沒有任何區別。

0

首先,您並未指向某個類,而是指向該類的一個實例(或對象)。在其他一些語言中,類實際上也是對象:-)

這個例子就是這樣一個例子。很可能你不會在那裏使用指針。

現在,什麼是指針?指針只是指向真實事物的小小事物。就像門鈴上的名牌 - 它顯示你的名字,但實際上並不是你。但是,因爲它不是你,所以你可以在不同的位置放置多個按鈕,並在其上放置你的名字。

這是使用指針的一個原因:如果你有一個對象,但是你想在不同的地方保持指向那個對象的指針。我的意思是,現實世界在各種地方都有很多「指針」應該不難想象程序在數據內可能需要類似的東西。

指針還用於避免必須複製周圍的物體,這可能是一項昂貴的操作。傳遞函數指針要便宜得多。另外,它允許函數修改對象(注意在技術上,C++「引用」也是指針,它只是稍微不明顯,而且更加有限)。

此外,分配有「新」的對象將保留,直到它們被釋放爲「刪除」。因此,他們不依賴於範圍界定 - 當他們周圍的功能完成時,它們不會消失,當它們被告知迷路時,它們只會消失。

另外,你會如何做一個「水果袋」?你分配一個「包」對象。然後你分配一個「水果」對象,並且你在包對象內設置一個指針指向水果對象,表明該包應該包含該水果。水果也可能會得到一個指向袋子對象的指針,這樣代碼在水果上工作也可以到達袋子。您還可以分配另一個「水果」對象,並建立一系列指針:每個「水果」可以有一個指向「下一個」水果的「下一個」指針,因此您可以將任意數量的水果放入包中:袋子包含一個指向第一個水果的指針,每個水果包含一個指向另一個水果的指針。所以你會得到一連串的成果。 (這是一個簡單的「容器」;有幾個這樣的類「包含」任意數量的對象)。

實際上並不是那麼簡單,拿出什麼時候或爲什麼指針被使用的描述;通常情況下你會需要它們的情況。當你遇到這種情況時,看到它們的有用性會容易得多。就像「爲什麼傘是有用的」一樣 - 一旦你踏入外面的瓢潑大雨,傘的用處將變得明顯。