?? c++10.dat
字號(hào):
private:
int width;
int height;
//...
};
Image::Image (const int w, const int h)
{
width = w;
height = h;
//...
}
其實(shí),類Image中的width和height的初始化也可以通過成員初始化表來初始化,例如:
程序段2
class Image {
public:
Image(const int w, const int h);
private:
int width;
int height;
//...
};
Image::Image (const int w, const int h) : width(w), height(h)
{
//...
}
這個(gè)定義的效果是width被w初始化,height被w初始化.用成員初始化表初始化類成員與用構(gòu)造函數(shù)初始化類成員的區(qū)別在于:前者的初始化是在構(gòu)造函數(shù)被執(zhí)行以前進(jìn)行的.
成員初始化表可用于初始化類的任意數(shù)據(jù)成員(后面要介紹的靜態(tài)數(shù)據(jù)成員除外),它被放在構(gòu)造函數(shù)的頭和體之間,并用冒號(hào)將它與構(gòu)造函數(shù)的頭分隔開.它由逗號(hào)分隔的數(shù)據(jù)成員表組成,初值放在一對(duì)圓括號(hào)中.
2.3 析構(gòu)函數(shù)
我們已經(jīng)知道,當(dāng)對(duì)象創(chuàng)建時(shí),會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù)進(jìn)行初始化.當(dāng)對(duì)象銷毀時(shí),也會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)進(jìn)行一些清理工作.與構(gòu)造函數(shù)類似的是:析構(gòu)函數(shù)也與類同名,但在名字前有一個(gè)~符號(hào),析構(gòu)函數(shù)也沒有返回類型和返回值.但析構(gòu)函數(shù)不帶參數(shù),不能重載,所以析構(gòu)函數(shù)只有一個(gè).
若一個(gè)對(duì)象中有指針數(shù)據(jù)成員,該指針數(shù)據(jù)成員指向某一個(gè)內(nèi)存塊.在對(duì)象銷毀前,往往通過析構(gòu)函數(shù)釋放該指針指向的內(nèi)存塊.例如,Set類中elems指針指向一個(gè)動(dòng)態(tài)數(shù)組,我們應(yīng)該給Set類再定義一個(gè)析構(gòu)函數(shù),使elems指向的內(nèi)存塊能夠在析構(gòu)函數(shù)中被釋放:
class Set
{
public:
Set (const int size);
~Set(void) {delete elems;} // 析構(gòu)函數(shù)
//...
private:
int *elems; // 集合元素
int maxCard; // 集合最大尺寸
int card; // 集合元素個(gè)數(shù)
};
下面我們通過一個(gè)例子,分析析構(gòu)函數(shù)是如何工作的:
void Foo (void)
{
Set s(10);
//...
}
當(dāng)函數(shù)Foo被調(diào)用時(shí),創(chuàng)建對(duì)象s,并調(diào)用其構(gòu)造函數(shù),為s.elems分配內(nèi)存及初始化其它對(duì)象成員.在Foo函數(shù)返回以前,s的析構(gòu)函數(shù)被調(diào)用,釋放s.elems指向的內(nèi)存區(qū).
注意:對(duì)象的析構(gòu)函數(shù)在對(duì)象銷毀前被調(diào)用,對(duì)象何時(shí)銷毀也與其作用域有關(guān).例如,全局對(duì)象是在程序運(yùn)行結(jié)束時(shí)銷毀,自動(dòng)對(duì)象是在離開其作用域時(shí)銷毀,而動(dòng)態(tài)對(duì)象則是在使用delete運(yùn)算符時(shí)銷毀.析構(gòu)函數(shù)的調(diào)用順序與構(gòu)造函數(shù)的調(diào)用順序相反.
用析構(gòu)函數(shù)確保對(duì)象的清除
我們常常不會(huì)忽略初始化的重要性,卻很少想到清除的重要性.實(shí)際上,清除也很重要,例如,我們?cè)诙阎猩暾?qǐng)了一些內(nèi)存,如果不在用完后就釋放,就會(huì)造成內(nèi)存泄露,它會(huì)導(dǎo)致應(yīng)用程序運(yùn)行效率降低,甚至崩潰,我們不可掉以輕心.在C++中,提供了析構(gòu)函數(shù),保證對(duì)象清除工作的自動(dòng)執(zhí)行.
析構(gòu)函數(shù)與構(gòu)造函數(shù)不同點(diǎn)是:析構(gòu)函數(shù)的功能與構(gòu)造函數(shù)相反,也不帶任何參數(shù),所以,它不能被重載.當(dāng)對(duì)象超出其作用域被銷毀時(shí),析構(gòu)函數(shù)會(huì)被自動(dòng)調(diào)用.
例
#include <iostream.h>
class Tree
{
int height;
public:
Tree (int initialHeight); //Constructor
~Tree (); //Destructor
void grow(int years);
void printsize();
};
Tree:: Tree (int initialHeight)
{
height = initialHeight;
}
Tree::~ Tree ()
{
cout<<"inside tree destructor"<<endl;
printsize();
}
void Tree::grow(int years)
{
height += years;
}
void Tree::printsize()
{
cout<<"tree height is "<<height<<endl;
}
void main()
{
cout<<"before opening brace"<<endl;
{
Tree t(12);
cout<<"after tree creation"<<endl;
t.printsize();
t.grow(4);
cout<<"before closing brace"<<endl;
}
cout<<"after closing brace"<<endl;
}
下面是上面程序的輸出結(jié)果:
before opening brace
after tree creation
tree height is 12
before closing brace
inside tree destructor
tree height is 16
after closing brace
我們可以看到,析構(gòu)函數(shù)在包含它的右括號(hào)處調(diào)用.
關(guān)于返回值
構(gòu)造函數(shù)和析構(gòu)函數(shù)是兩個(gè)非常特殊的函數(shù):它們沒有返回值.這與返回值為void的函數(shù)是不同的.后者雖然也不返回任何值,但有返回類型,而構(gòu)造函數(shù)和析構(gòu)函數(shù)根本就沒有返回類型.
2.4 缺省的構(gòu)造函數(shù)和析構(gòu)函數(shù)
前面我們介紹了構(gòu)造函數(shù)和析構(gòu)函數(shù)的特點(diǎn)、功能及應(yīng)用.當(dāng)用戶未顯式定義構(gòu)造函數(shù)和析構(gòu)函數(shù)時(shí),編譯器會(huì)隱式定義一個(gè)內(nèi)聯(lián)的、公有的構(gòu)造函數(shù)和析構(gòu)函數(shù).
缺省的構(gòu)造函數(shù)執(zhí)行創(chuàng)建一個(gè)對(duì)象所需要的一些初始化操作,但它并不涉及用戶定義的數(shù)據(jù)成員或申請(qǐng)的內(nèi)存的初始化.例
class C
{
private:
int n;
char *p;
public:
virtual ~C() {}
};
void f()
{
C obj; //隱式定義的構(gòu)造函數(shù)被調(diào)用
}
類C沒有顯式定義構(gòu)造函數(shù),一個(gè)隱式缺省的構(gòu)造函數(shù)被定義.在函數(shù)f中,定義對(duì)象obj時(shí),調(diào)用該構(gòu)造函數(shù),但它并不初始化數(shù)據(jù)成員n和p,也不為后者分配內(nèi)存.
同樣,缺省的的析構(gòu)函數(shù)也不涉及釋放用戶申請(qǐng)的內(nèi)存的釋放等清理工作.
第三節(jié) 復(fù)制構(gòu)造函數(shù)
對(duì)一個(gè)簡(jiǎn)單變量的初始化方法是用一個(gè)常量或變量初始化另一個(gè)變量,例如:
int m = 80;
int n = m;
我們已經(jīng)會(huì)用構(gòu)造函數(shù)初始化對(duì)象,那么我們能不能象簡(jiǎn)單變量的初始化一樣,直接用一個(gè)對(duì)象來初始化另一個(gè)對(duì)象呢?答案是肯定的.我們以前面定義的Point類為例:
Point pt1(15, 25);
Point pt2 = pt1;
后一個(gè)語句也可以寫成:
Point pt2( pt1);
它是用pt1初始化pt2,此時(shí),pt2各個(gè)成員的值與pt1各個(gè)成員的值相同,也就是說,pt1各個(gè)成員的值被復(fù)制到pt2相應(yīng)的成員當(dāng)中.在這個(gè)初始化過程當(dāng)中,實(shí)際上調(diào)用了一個(gè)復(fù)制構(gòu)造函數(shù).當(dāng)我們沒有顯式定義一個(gè)復(fù)制構(gòu)造函數(shù)時(shí),編譯器會(huì)隱式定義一個(gè)缺省的復(fù)制構(gòu)造函數(shù),它是一個(gè)內(nèi)聯(lián)的、公有的成員,它具有下面的原型形式:
Point:: Point (const Point &);
可見,復(fù)制構(gòu)造函數(shù)與構(gòu)造函數(shù)的不同之處在于形參,前者的形參是Point對(duì)象的引用,其功能是將一個(gè)對(duì)象的每一個(gè)成員復(fù)制到另一個(gè)對(duì)象對(duì)應(yīng)的成員當(dāng)中.
雖然沒有必要,我們也可以為Point類顯式定義一個(gè)復(fù)制構(gòu)造函數(shù):
Point:: Point (const Point &pt)
{
xVal=pt. xVal;
yVal=pt. yVal;
}
如果一個(gè)類中有指針成員,使用缺省的復(fù)制構(gòu)造函數(shù)初始化對(duì)象就會(huì)出現(xiàn)問題.為了說明存在的問題,我們假定對(duì)象A與對(duì)象B是相同的類,有一個(gè)指針成員,指向?qū)ο驝.當(dāng)用對(duì)象B初始化對(duì)象A時(shí),缺省的復(fù)制構(gòu)造函數(shù)將B中每一個(gè)成員的值復(fù)制到A的對(duì)應(yīng)的成員當(dāng)中,但并沒有復(fù)制對(duì)象C.也就是說,對(duì)象A和對(duì)象B中的指針成員均指向?qū)ο驝.
第四節(jié) 類作用域
我們已經(jīng)學(xué)習(xí)了局部作用域和全局作用域,下面介紹類作用域,所有的類成員是屬于類作用域的.
類本身可被定義在三種作用域內(nèi):
1. 全局作用域.這是所謂全局類,絕大多數(shù)的C++類是定義在該作用域中,我們?cè)谇懊娑x的所有類都是在全局作用域中.
2. 在另一個(gè)類的作用域中.這是所謂嵌套類,即一個(gè)類包含在另一個(gè)類中.
3. 在一個(gè)塊的局部作用域中.這是所謂局部類,該類完全被塊包含.
例如:
int fork (void); // 全局fork
class Process {
int fork (void);
//...
};
成員函數(shù)fork隱藏了全局函數(shù)fork,前者能通過單目域運(yùn)算符調(diào)用后者:
int Process::fork (void)
{
int pid = ::fork(); // 使用全局fork
//...
}
下面舉一個(gè)嵌套類的例子.
例
class Rectangle {
public:
Rectangle (int, int, int, int);
//..
private:
class Point {
public:
Point (int, int);
private:
int x, y;
};
Point topLeft, botRight;
};
類Point嵌套在Rectangle類中,Point成員函數(shù)可定義為內(nèi)聯(lián)的,也可在全局作用域中,但后者對(duì)成員函數(shù)名需要更多的限制,例如:
Rectangle::Point::Point (int x, int y)
{
//...
}
同樣,在類域外訪問嵌套類需要限制類名,例如:
Rectangle::Point pt(1,1);
下面我們?cè)倏匆粋€(gè)局部類的例子:
例
void Render (Image &image)
{
class ColorTable {
public:
ColorTable(void) { /* ... */ }
AddEntry(int r, int g, int b) { /* ... */ }
//...
};
ColorTable colors;
//...
}
類ColorTable是在函數(shù)Render中的局部類.與嵌套類不同的是:局部類不能在其局部作用域外訪問,例如:
ColorTable ct; // 非法,沒有定義ColorTable類!
局部類必須完全定義在局部作用域內(nèi).所以,它的所有成員函數(shù)必須是內(nèi)聯(lián)的,這就決定了局部類的成員函數(shù)都是很簡(jiǎn)單的.
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -