問題:動態內存分配和指針之間怎麼使用?
使用new,返回的內存從所謂堆(heap),即由C++運行時管理的內存區域開始分配,如何訪問呢?就是使用指針,例如,
int *pNumber =new int(2001);
Star *pStar = new Star(1234.5,10.2);
當分配一個帶有構造函數的對象時,初始化是強制性的。即使一個對象沒有顯式構造函數,編譯器也可能不得不生成一些代碼來構建它:
若一個類沒有有效的構造函數,編譯器將產生一個缺省的無參數構造函數;
若一個類有一個顯式定義的無參數構造函數,則就在分配的時候調用;
若一個類只有一個帶參數的構造函數,比如叫做CBody類,則CBody *bodes = new CBody[100];編譯器將不予編譯。
所以在定義CBody的時候可以使用如下的構造函數:
CBody (double mass =0.0):_mass(mass){}
這等價於具備參數個數為0和1的兩個重載構造函數。
為了釋放則使用delete,例如,delete pNumber;若有析構函數則自動調用,例如,delete pStar;
若想刪除數組則在其前邊放上[],例如: delete [] pNumbers;
刪除一個空指針是安全的,所以在調用delete前不需要檢查是否為空指針。
問題:如何實現鏈表?
List.h
view plaincopy to clipboardprint?
#if !defined (LIST_H)
#define LIST_H
// (c) Bartosz Milewski 2000
class Link
{
public:
Link (Link* pNext, int id)
: _pNext (pNext), _id (id) {}
Link * Next () const { return _pNext; }
int Id () const { return _id; }
private:
int _id;
Link * _pNext;
};
class List
{
public:
List (): _pHead (0) {}
~List ();
void Add ( int id );
Link const * GetHead () const { return _pHead; }
private:
Link* _pHead;
};
#endif
#if !defined (LIST_H)
#define LIST_H
// (c) Bartosz Milewski 2000
class Link
{
public:
Link (Link* pNext, int id)
: _pNext (pNext), _id (id) {}
Link * Next () const { return _pNext; }
int Id () const { return _id; }
private:
int _id;
Link * _pNext;
};
class List
{
public:
List (): _pHead (0) {}
~List ();
void Add ( int id );
Link const * GetHead () const { return _pHead; }
private:
Link* _pHead;
};
#endif
List.cpp
view plaincopy to clipboardprint?
// (c) Bartosz Milewski 2000
#include "List.h"
#include <iostream>
List::~List ()
{
// free the list
while ( _pHead != 0 )
{
Link* pLink = _pHead;
_pHead = _pHead->Next(); // unlink pLink
delete pLink;
}
}
void List::Add ( int id )
{
// add in front of the list
Link * pLink = new Link (_pHead, id);
_pHead = pLink;
}
int main ()
{
List list;
list.Add (1);
list.Add (2);
std::cout << "List contents:
";
for (Link const * pLink = list.GetHead();
pLink != 0;
pLink = pLink->Next ())
{
std::cout << pLink->Id() << ", ";
}
std::cout << std::endl;
}
// (c) Bartosz Milewski 2000
#include "List.h"
#include <iostream>
List::~List ()
{
// free the list
while ( _pHead != 0 )
{
Link* pLink = _pHead;
_pHead = _pHead->Next(); // unlink pLink
delete pLink;
}
}
void List::Add ( int id )
{
// add in front of the list
Link * pLink = new Link (_pHead, id);
_pHead = pLink;
}
int main ()
{
List list;
list.Add (1);
list.Add (2);
std::cout << "List contents:
";
for (Link const * pLink = list.GetHead();
pLink != 0;
pLink = pLink->Next ())
{
std::cout << pLink->Id() << ", ";
}
std::cout << std::endl;
}
我們要注意區分的是指向常量的指針和常量指針,前者所指向的想對象不能通過此指針來修改,後者則表示一旦初始化,就不能指向其他任何對象。
Link const *pLink;//指向常量的指針
Link * const pLink = pInitPtr;//常量指針
可以組合為指向常量的常量指:
Link Const * const pLink=pInitPtr;
我們從右往左念,星號表示“指向一個”,這樣就好理解記憶了。
另外,const作為返回值的一些東西也需要我們注意:我們經常看到一些函數返回const char*後者返回char *,這有什麼區別呢?
const char*說明函數返回一個你不能改變指針所指向單元值的指針. 也就是說指針所指向的值是一個常數,你不能通過*操作來改變它的值.
而char*則可以改變指針所指向的值.要是不需要處理返回值,或者不允許處理返回值的話,那麼其實使用前者比較好。
再一個問題:用const修飾引用,通過引用本身不可修改其值,但這並不耽誤被引用變量的被外界修改。Const加在數據類型前後均可。
例如:void main(void)
{
int i = 10;
int j = 100;
const int &r = i;
int const &s = j;
r = 20; //錯,不能改變內容
s = 50; //錯,不能改變內容
i = 15; // i和r 都等於15
&nb