構造函數與析構函數
OOP第二課
1、構造函數
1.1 構造函數具有一些特殊的性質
1.2 定義構造函數的一般形式
1.3 利用構造函數創(chuàng)建對象
2、成員初始化表
3、缺省參數的構造函數
4旧找、重載構造函數
5、拷貝構造函數
5.1 自定義拷貝構造函數
5.2 缺省的拷貝構造函數
5.3 調用拷貝構造函數的三種情況
5.4 淺拷貝和深拷貝
6麦牺、析構函數
7钮蛛、調用構造函數和析構函數的順序
8、對象的生存期
創(chuàng)一個小群剖膳,供大家學習交流聊天
如果有對學C++方面有什么疑惑問題的魏颓,或者有什么想說的想聊的大家可以一起交流學習一起進步呀。
也希望大家對學C++能夠持之以恒
C++愛好群吱晒,
如果你想要學好C++最好加入一個組織甸饱,這樣大家學習的話就比較方便,還能夠共同交流和分享資料,給你推薦一個學習的組織:快樂學習C++組織 可以點擊組織二字叹话,可以直達
構造函數和析構函數都是類的成員函數,但它們都是特殊的成員函數,執(zhí)行特殊的功能,不用調用便自動執(zhí)行,而且這些函數的名字與類的名字有關偷遗。
C++語言中有一些成員函數性質是特殊的,這些成員函數負責對象的建立驼壶、刪除氏豌。這些函數的特殊性在于可以由編譯器自動地隱含調用,其中一些函數調用格式采用運算符函數重載的語法热凹。
C++引進一個自動完成對象初始化過程的機制泵喘,這就是類的構造函數。
對象的初始化
1般妙、數據成員是不能在聲明類時初始化
2纪铺、類型對象的初始化方法:
1) 調用對外接口(public成員函數)實現(xiàn):聲明類→定義對象→調用接口給成員賦值
2) 應用構造函數(constructor) 實現(xiàn):聲明類→定義對象→同時給成員賦值
1、構造函數
構造函數是一種特殊的成員函數,它主要用于為對象分配空間,進行初始化碟渺。
1.1 構造函數具有一些特殊的性質:
(1) 構造函數的名字必須與類名相同霹陡。
(2) 構造函數可以有任意類型的參數,但不能指定返回類型。 它有隱含的返回值,該值由系統(tǒng)內部使用止状。
(3) 構造函數是特殊的成員函數,函數體可寫在類體內,也可寫在類體外。
(4) 構造函數可以重載,即一個類中可以定義多個參數個數或參數類型不同的構造函數攒霹。構造函數是不能繼承
(5) 構造函數被聲明為公有函數,但它不能像其他成員函數那樣被顯式地調用,它是在定義對象的同時被調用的怯疤。
(6) 在聲明類時如果沒有定義類的構造函數,編譯系統(tǒng)就會在編譯時自動生成一個默認形式的構造函數催束,
(7)?默認構造函數是構造對象時不提供參數的構造函數集峦。
(8) 除了無參數構造函數是默認構造函數外,帶有全部默認參數值的構造函數也是默認構造函數抠刺。
(9)?自動調用:構造函數在定義類對象時自動調用塔淤, 不需用戶調用,也不能被用戶調用速妖。在對象使用前調用高蜂。
(10)?調用順序:在對象進入其作用域時(對象使用前) 調用構造函數。
1.2 定義構造函數的一般形式
class類名
{
public:
類名(形參表)?;//構造函數的原型
//類的其它成員
};
類名::類名(形參表)//構造函數的實現(xiàn)
{
//函數體
}
1.3 利用構造函數創(chuàng)建對象
(1) 利用構造函數直接創(chuàng)建對象.其一般形式為:類名 對象名[(實參表)];
這里的“類名”與構造函數名相同,“實參表”是為構造函數提供的實際參數罕容。
例2.7 為類Date建立一個構造函數
#include<iostream.h>
classDate{
public:
Date(inty,intm,intd);//?構造函數
voidsetDate(inty,intm,intd);
voidshowDate();
private:
intyear,?month,?day;
};
Date::Date(inty,intm,intd)//?構造函數的實現(xiàn)
{?year=y;?month=m;?day=d;?}
voidDate::setDate(inty,intm,intd)
{?year=y;?month=m;?day=d;?}
inlinevoidDate::showDate()
{cout<
例2.8 利用構造函數直接創(chuàng)建對象
#include<iostream.h>
classDate{
//?省略备恤,?同例2.7
};
//?省略,?同例2.7
voidmain()
{
Datedate1(1998,4,28);//?定義類Date的對象date1,
//?自動調用date1的構造函數,初始化對象date1
cout<<"Date1?output1:"<
date1.showDate();//?調用date1的showDate(),顯示date1的數據
date1.SetDate(2002,11,14);//?調用date1的setDate(),
//?重新設置date1的數據
cout<<"Date1?output2:"<
date1.showDate();//?調用date1的showDate(),顯示date1的數據
}
constructing...
Date1output1:
1998.4.28
Date1output2:
2002.11.14
(2) 利用構造函數創(chuàng)建對象時,通過指針和new來實現(xiàn)锦秒。其一般語法形式為:
類名 *指針變量 = new 類名[(實參表)];
voidmain()
{
Date?*date1;
date1=newDate(1998,4,28);
//可合寫成:Date?*date1=new?Date(1998,4,28);
cout<<"Date1?output1:"<
date1->showDate();
date1->setDate(2002,11,14);
cout<<"Date1?output2:"<
date1->showDate();
deletedate1;
}
說明:
構造函數的名字必須與類名相同露泊,否則編譯器將把它當作一般的成員函數來處理。
構造函數是不能說明它的返回值類型的旅择,甚至說明為void類型也不行惭笑。
構造函數可以是不帶參數的。
classA{
public:
A();
//…
private:
intx;
};
A∷A()
{
cout<<"initialized?\n";
x=50;
}
main()
{
A?a;
…
}
例
有兩個長方柱,其長沉噩、寬捺宗、高分別為:(1)12,25,30;(2)15,30,21屁擅。求它們的體積偿凭。要求:編一個基于對象的程序,在類中用帶參數的構造函數派歌。
classBox{
public:
Box(int,int,int);
intvolume(?);
private:
intheight;
intwidth;
intlength;
};
Box::Box(inth,intw,intlen)
{
height?=?h;
width?=?w;
length?=?len;
}
intBox::volume(?)
{
returnheight*width*length;
}
intmain(?)
{
Boxbox1(12,25,30);
cout<<?box1.volume(?)?<
Boxbox2(15,30,21);
cout<<?box2.volume(?)?<
return0;
}
2弯囊、成員初始化表
對于常量類型和引用類型的數據成員,不能在構造函數中用賦值語句直接賦值,C++提供初始化表進行置初值。
帶有成員初始化表的構造函數的一般形式如下:
類名::構造函數名([參數表])[:(成員初始化表)]
{
// 構造函數體
}
成員初始化表的一般形式為:
數據成員名1(初始值1),數據成員名2(初始值2),……
例2.9 成員初始化表的使用
#include<iostream.h>
classA{
public:
A(intx1):x(x1),rx(x),pi(3.14)//?rx(x)相當于rx=x,?pi(3.14)相當于pi=3.14
{?}
voidprint()
{cout<<"x="<
private:
intx;int&?rx;constfloatpi;
};
main()
{
Aa(10);
a.print();
return0;
}
構造函數采用成員初始化表對數據成員進行初始化胶果,是一些程序員喜歡使用的方法匾嘱。
classB{
inti;
charj;
floatf;
public:
B(intI,charJ早抠,floatF)
{?i=I;?j=J;?f=F;?};
};
classB{
public:
B(intI,charJ,floatF):i(I),j(J),f(F)
{?}
private:
inti;
charj;
floatf;
};
說明
如果需要將數據成員存放在堆中或數組中霎烙,則應在構造函數中使用賦值語句,即使構造函數有成員初始化表也應如此蕊连。
classC{
public:
C(int?I,char?Ch,float?F,char?N[]):i(I),ch(Ch),f(F)
{?strcpy?(name,N);}
private:
inti;
charch;
floatf;
charname[25];
};
類成員是按照它們在類里被聲明的順序初始化的,與它們在初始化表中列出的順序無關悬垃。
【例2.10】
#include<iostream.h>
classD{
public:
D(inti):mem2(i),mem1(mem2+1)
{
cout<<"mem1:?"<
cout<<"mem2:?"<
}
private:
intmem1;
intmem2;
};
voidmain()
{
Dd(15);
}
mem1:?-858993459
mem2:?15
3、缺省參數的構造函數
例2.11
#include<iostream.h>
classCoord{
public:
Coord(inta=0,intb=0){?x=a;?y=b;}//?帶有缺省參數的構造函數
intgetx(){returnx;?}
intgety(){returny;?}
private:
intx,y;
};
voidmain()
{
Coordop1(5,6);Coordop2(5);?Coord?op3;
inti,j;
i=op1.getx();j=op1.gety();
cout<<"op1?i=?"<
i=op2.getx();j=op2.gety();
cout<<"op2?i=?"<
i=op3.getx();j=op3.gety();
cout<<"op3?i=?"<
}
classBox{
public:
Box(inth=10,intw=10,intl=10);//在聲明構造函數時指定默認參數
intvolume(?){return(height*width*length);?}
private:
intheight;
intwidth;
intlength;
};
Box::?Box(inth,intw,intl)//在定義函數時可以不指定默認參數
{
height=h;
width=w;
length=l;
}
4甘苍、重載構造函數
構造函數的重載
在一個類中可以定義多個構造函數尝蠕,以便對類對象提供不同的初始化的方法,供用戶選用载庭。這些構造函數具有相同的名字看彼,而參數的個數或參數的類
型不相同(這稱為構造函數的重載)
關于構造函數重載的說明
(1)?默認構造函數:一個調用構造函數時不必給出實參的構造函數。 顯然囚聚,無參的構造函數屬于默認構造函數靖榕。一個類只能有一個默認構造函數。
(2) 盡管在一個類中可以包含多個構造函數顽铸,但是對于每一個對象來說茁计,建立對象時只執(zhí)行其中一個構造函數,并非每個構造函數都被執(zhí)行跋破。
classBox{
public:
Box(inth,intw,intl):?height(h),width(w),length(l)?{?}
Box();
intvolume(?);
private:
intheight;
intwidth;
intlength;
};
Box::Box()
{
height?=10;
width?=10;
lenght?=10;
}
intBox::volume(?)
{
returnheight*width*length;
}
intmain(?)
{
Box?box1;//?書上為?box1();
cout<<?box1.volume(?)?<
Boxbox2(15,30,25);
cout<<?box2.volume(?)?<
return0;
}
例2.17 重載構造函數應用例程簸淀。
#include<iostream.h>
classDate{
public:
Date();//?無參數的構造函數
Date(inty,intm,intd);//?帶有參數的構造函數
voidshowDate();
private:
intyear,?month,?day;
};
Date::Date()
{?year=1998;?month=4;?day=28;?}
Date::Date(inty,intm,intd)
{?year=y;?month=m;?day=d;?}
inlinevoidDate::showDate()
{cout<
voidmain()
{
Date?date1;//?聲明類Date的對象date1,
//?調用無參數的構造函數
cout<<"Date1?output:?"<
date1.showDate();//?調用date1的showDate()毒返,顯示date1的數據
Datedate2(2002租幕,11,14);//?定義類Date的對象date2拧簸,
//?調用帶參數的構造函數
cout<<"Date2?output:?"<
date2.showDate();//?調用date2的showDate()交排,顯示date2的數據
}
運行結果:
Date1output:
1998.4.28
Date2output:
2002.11.14
例2.18 關于計時器的例子
#include<iostream.h>
#include<stdlib.h>
classtimer{
public:
timer()//?無參數構造函數,給seconds清0
{?seconds=0;?}
timer(char*?t)//?含一個數字串參數的構造函數
{?seconds=atoi(t);?}
timer(intt)//?含一個整型參數的構造函數
{?seconds=t;?}
timer(intmin,intsec)//?含兩個整型參數的構造函數
{?seconds=min*60+sec;?}
intgettime()
{returnseconds;?}
private:
intseconds;
};
main()
{
timer?a,b(10),c("20"),d(1,10);
cout<<"seconds1="<
cout<<"seconds2="<
cout<<"seconds3="<
cout<<"seconds4="<
return0;
}
classx{
public:
x();//?沒有參數的構造函數
x(inti=0);//?帶缺省參數的構造函數
};
//…
voidmain()
{
xone(10);//?正確,調用x(int?i=0)
x?two;//?存在二義性
//…
}
5透乾、拷貝構造函數
拷貝構造函數是一種特殊的構造函數,其形參是本類對象的引用步淹。其作用是使用一個已經存在的對象去初始化另一個同類的對象。
通過等于號復制對象時歉眷,系統(tǒng)會自動調用拷貝構造函數。
拷貝構造函數與原來的構造函數實現(xiàn)了函數的重載颤枪。
拷貝構造函數具有以下特點:
(1) 因為該函數也是一種構造函數,所以其函數名與類名相同,并且該函數也沒有返回值類型汗捡。
(2) 該函數只有一個參數,并且是同類對象的引用。
(3) 每個類都必須有一個拷貝構造函數畏纲。程序員可以根據需要定義特定的拷貝構造函數,以實現(xiàn)同類對象之間數據成員的傳遞扇住。如果程序員沒有定義類的拷貝構造函數,系統(tǒng)就會自動生成產生一個缺省的拷貝構造函數。
5.1 自定義拷貝構造函數
自定義拷貝構造函數的一般形式如下:
class類名{
public:
類名(形參)盗胀;//構造函數
類名(類名?&對象名)艘蹋;//拷貝構造函數
...
};
類名::?類名(類名?&對象名)//拷貝構造函數的實現(xiàn)
{?函數體?}
用戶自定義拷貝構造函數
classCoord{
intx,y;
public:
Coord(inta票灰,intb)//?構造函數
{
x=a;
y=b;
cout<<"Using?normal?constructor\n";
}
Coord(constCoord&?p)//?拷貝構造函數
{
x=2*p.x;
y=2*p.y;
cout<<"Using?copy?constructor\n";
}
//…
};
如果p1女阀、 p2為類Coord的兩個對象,p1已經存在屑迂,則coord p2(p1)調用拷貝構造函數來初始化p2
例2.19 自定義拷貝構造函數的使用
#include<iostream.h>
classCoord{
public:
Coord(inta,intb)//?構造函數
{?x=a;?y=b;cout<<"Using?normal?constructor\n";}
Coord(constCoord&?p)//?拷貝構造函數
{?x=2*p.x;?y=2*p.y;cout<<"Using?copy?constructor\n";}
voidprint(){cout<
private:
intx,y;
};
main()
{
Coordp1(30,40);//?定義對象p1,調用了普通的構造函數
Coordp2(p1);//?以“代入”?法調用拷貝構造函數,用對象p1初始化對象p2
p1.print();
p2.print();
return0;
}
除了用代入法調用拷貝構造函數外浸策,還可以采用賦值法調用拷貝構造函數,如:
main()
{
Coordp1(30,40);
Coord?p2=p1;//以"賦值"法調用拷貝構造函數惹盼,
用對象p1初始化對象p2
//…
}
5.2 缺省的拷貝構造函數
如果沒有編寫自定義的拷貝構造函數,C++會自動地將一個已存在的對象復制給新對象,這種按成員逐一復制的過程由是缺省拷貝構造函數自動完成的的榛。
例2.20 調用缺省的拷貝構造函數
#include<iostream.h>
classCoord{
public:
Coord(inta,intb)
{?x=a;?y=b;cout<<"Using?normal?constructor\n";?}
voidprint(){cout<
private:
intx,y;
};
main()
{
Coordp1(30,40);//?定義類Coord的對象p1,
//?調用了普通構造函數初始化對象p1
Coordp2(p1);//?以“代入”法調用缺省的拷貝構造函數,
//?用對象p1初始化對象p2
Coord?p3=p1;//?以“賦值”法調用缺省的拷貝構造函數,
//?用對象p1初始化對象p3
p1.print();?p2.print();?p3.print();
return0;
}
5.3 調用拷貝構造函數的三種情況
(1) 當用類的一個對象去初始化該類的另一個對象時。
Coordp2(p1);//?用對象p1初始化對象p2,?拷貝構造函數被調用(代入法)
Coord?p3=p1;//?用對象p1初始化對象p3,?拷貝構造函數被調用(賦值法)
(2) 當函數的形參是類的對象,調用函數,進行形參和實參結合時逻锐。
//…
fun1(Coord?p)//?函數的形參是類的對象
{
p.print();
}
main()
{
Coordp1(10,20);
fun1(p1);//?當調用函數,進行形參和實參結合時,
調用拷貝構造函數
return0;
}
(3) 當函數的返回值是對象,函數執(zhí)行完成,返回調用者時。
//?…
Coordfun2()
{
Coordp1(10,30);
returnp1;
}//?函數的返回值是對象
main()
{
Coord?p2;
P2=fun2();//?函數執(zhí)行完成,返回調用者時,調用拷貝構造函數
return0;
}
5.4 淺拷貝和深拷貝
所謂淺拷貝雕薪,就是由缺省的拷貝構造函數所實現(xiàn)的數據成員逐一賦值昧诱,若類中含有指針類型數據, 則會產生錯誤所袁。
為了解決淺拷貝出現(xiàn)的錯誤盏档,必須顯示地定義一個自己的拷貝構造函數,使之不但拷貝數據成員燥爷,而且為對象1和對象2分配各自的內存空間蜈亩,這就是所謂的深拷貝。
例2.23 淺拷貝例子
#include<iostream.h>
#include<string.h>
classStudent{
public:
Student(char*name1,floatscore1);
~Student();
private:
char*name;//?學生姓名
floatscore;//?學生成績
};
Student∷Student(char*name1,floatscore1)
{
cout<<"Constructing..."<
name=newchar[strlen(name1)+1];
if(name?!=0)
{
strcpy(name,name1);
score=score1;
}
}
Student∷~Student()
{
cout<<"Destructing..."<
name[0]='\0';
deletename;
}
voidmain()
{
Studentstu1("liming",90);//?定義類Student的對象stu1
Student?stu2=stu1;//?調用缺省的拷貝構造函數
}
Constructing...?liming
Destructing...?liming
Destructing...
淺拷貝示意圖
例2.24 深拷貝例子
#include<iostream.h>
#include<string.h>
classStudent{
private:
char*name;//?學生姓名
floatscore;//?學生成績
public:
Student(char*name1,floatscore1);
Student(Student&?stu);
~Student();
};
Student∷Student(char*name1,floatscore1)
{
cout<<"constructing..."<
name=newchar[strlen(name1)+1];
if(name?!=0)
{
strcpy(name,name1);
score=score1;
}
}
Student∷Student(Student&?stu)
{
cout<<"Copy?constructing..."<
name=newchar[strlen(stu.name)+1];
if(name?!=0)
{
strcpy(name,stu.name);
score=stu.score;
}
}
Student∷~Student()
{
cout<<"Destructing..."<
name[0]='\0';
deletename;
}
voidmain()
{
Studentstu1("liming"前翎,90);//?定義類Student的對象stu1稚配,
Student?stu2=stu1;//?調用自定義的拷貝構造函數
}
深拷貝示意圖
6、析構函數
析構函數也是一種特殊的成員函數港华。它執(zhí)行與構造函數相反的操作,通常用于撤消對象時的一些清理任務,如釋放分配給對象的內存空間等道川。
析構函數有以下一些特點:
① 析構函數與構造函數名字相同,但它前面必須加一個波浪號(~);
② 析構函數沒有參數,也沒有返回值,而且不能重載。因此在一個類中只能有一個析構函數;
③ 當撤消對象時,編譯系統(tǒng)會自動地調用析構函數。 如果程序員沒有定義析構函數冒萄,系統(tǒng)將自動生成和調用一個默認析構函數臊岸,默認析構函數只能釋放對象的數據成員所占用的空間,但不包括堆內存空間尊流。
例2.25 重新說明類Date
#include<iostream.h>
classDate{
public:
Date(inty,intm,intd);//?構造函數
~Date();//?析構函數
voidsetDate(inty,intm,intd);
voidshowDate();
private:
intyear,?month,?day;
};
Date::Date(inty,intm,intd)//?構造函數的實現(xiàn)
{
cout<<"constructing..."<
year=y;month=m;?day=d;
}
Date::~Date()//?析構函數的實現(xiàn)
{cout<<"destruting..."<
voidDate::setDate(inty,intm,intd)
{?year=y;month=m;day=d;?}
inlinevoidDate::showDate()
{cout<
voidmain()
{
Datedate1(1998,4,28);//?定義類Date的對象date1,
//?調用date1的構造函數,初始化對象date1
cout<<"Date1?output1:"<
date1.showDate();//?調用date1的showDate(),顯示date1的數據
date1.setDate(2002,11,14);//?調用date1的setDate(),
//?重新設置date1的數據
cout<<"Date1?output2:"<
date1.showDate();//?調用date1的showDate(),顯示date1的數據
}
析構函數被調用的兩種情況
1) 若一個對象被定義在一個函數體內帅戒,當這個函數結束時,析構函數被自動調用崖技。
2) 若一個對象是使用new運算符動態(tài)創(chuàng)建逻住,在使用delete釋放時,自動調用析構函數响疚。
【例2.13】 較完整的學生類例子
#include<iostream.h>
#include<string.h>
classStudent{
public:
Student(char*name1,char*stu_no1,floatscore1);//?構造
函數
~Student();//?析構函數
voidmodify(floatscore1);//?修改數據
voidshow();//?顯示數據
private:
char*name;//?學生姓名
char*stu_no;//?學生學號
floatscore;//?學生成績
};
Student∷Student(char*name1,char*stu_no1,floatscore1)
{
name=newchar[strlen(name1)+1];
strcpy(name,name1);
stu_no=newchar[strlen(stu_no1)+1];
strcpy(stu_no,stu_no1);
score=score1;
}
Student∷~Student()
{
delete[]name;
delete[]stu_no;
}
voidStudent∷modify(floatscore1)
{?score=score1;?}
voidStudent∷show()
{
cout<<"\n?name:?"<
cout<<"\n?stu_no:?"<
cout<<"\n?score:?"<
}
voidmain()
{
Studentstu1("Liming","990201",90);//?定義類Student的對象stu1,
//?調用stu1的構造函數,初始化對象stu1
stu1.show();//?調用stu1的show(),顯示stu1的數據
stu1.modify(88);//?調用stu1的modify(),修改stu1的數據
stu1.show();//?調用stu1的show(),顯示stu1修改后的數據
}
ame:Liming
stu_no:990201
score:90
name:Liming
stu_no:990201
score:88
缺省的析構函數
每個類必須有一個析構函數鄙信。
若沒有顯式地為一個類定義析構函數,編譯系統(tǒng)會自動地生成一個缺省的析構函數
其格式如下:類名::析構函數名( ){ }
classstring_data{
public:
string_data(char*)
{?str=newchar[max_len];}
~string_data()
{delete[]str;}
voidget_info(char*);
voidsent_info(char*);
private:
char*str;
intmax_len;
};
7忿晕、調用構造函數和析構函數的順序
1) 一般順序
調用析構函數的次序正好與調用構造函數的次序相反:最先被調用的構造函數装诡,其對應的(同一對象中的)析構函數最后被調用,而最后被調用的構造函數践盼,其對應的析構函數最先被調用鸦采。
2) 全局對象
在全局范圍中定義的對象(即在所有函數之外定義的對象),它的構造函數在所有函數(包括main函數)執(zhí)行之前調用咕幻。在程序的流程離開其作用域時(如main函數結束或調用exit函數)時渔伯,調用該全局對象的析構函數。
3) auto局部對象
局部自動對象(例如在函數中定義的對象)肄程,則在建立對象時調用其構造函數锣吼。如果函數被多次調用,則在每次建立對象時都要調用構造函數蓝厌。在函數調用結束玄叠、對象釋放時先調用析構函數。
4) static局部對象
如果在函數中定義靜態(tài)局部對象拓提,則只在程序第一次調用此函數建立對象時調用構造函數一次读恃,在調用結束時對象并不釋放,因此也不調用析構函數代态,只在main函數結束或調用exit函數結束程序時寺惫,才調用析構函數。
8. 對象的生存期
對象按生存期的不同分為如下幾種:
(1) 局部對象
當對象被定義時蹦疑,調用構造函數西雀,該對象被創(chuàng)建;當程序退出該對象所在的函數體或程序塊時歉摧,調用析構函數蒋搜,對象被釋放篡撵。
局部對象是被定義在一個函數體或程序塊內的,它的作用域限定在函數體或程序塊內豆挽,生存期較短育谬。
(2) 全局對象
當程序開始運行時,調用構造函數帮哈,該對象被創(chuàng)建膛檀;當程序結束時,調用析構函數娘侍,該對象被釋放咖刃。
靜態(tài)對象是被定義在一個文件中,它的作用域從定義是起到文件結束時為止憾筏。生存期較長嚎杨。
(3) 靜態(tài)對象
當程序中定義靜態(tài)對象時,調用構造函數氧腰,該對象被創(chuàng)建枫浙;當整個程序結束時,調用析構函數古拴,對象被釋放箩帚。
全局對象是被定義在某個文件中,它的作用域包含在該文件的整個程序中黄痪,生存期是最長的紧帕。
(4) 動態(tài)對象
執(zhí)行new運算符調用構造函數,動態(tài)對象被創(chuàng)建桅打;用delete釋放對象時是嗜,調用析構函數。
動態(tài)對象是由程序員掌握的挺尾,它的作用域和生存期是由new和delete之間的間隔決定的叠纷。
類的應用舉例(例)
一圓形游泳池如圖所示,現(xiàn)在需在其周圍建一圓形過道潦嘶,并在其四周圍上柵欄。柵欄價格為35元/米崇众,過道造價為20元/平方米掂僵。過道寬度為3米,游泳池半徑由鍵盤輸入顷歌。要求編程計算并輸出過道和柵欄的造價锰蓬。
#include<iostream>
usingnamespacestd;
constfloatPI?=3.14159;
constfloatFencePrice?=35;
constfloatConcretePrice?=20;
//聲明類Circle?及其數據和方法
classCircle{
private:
floatradius;
public:
Circle(floatr);//構造函數
floatCircumference()const;//圓周長
/*函數后的修飾符const表示該成員函數的執(zhí)行不會改變類的狀態(tài),也就是說不會修改類的數據成員眯漩。?*/
floatArea()const;//圓面積
};//?類的實現(xiàn)
//?構造函數初始化數據成員radius
Circle::Circle(floatr)
{
radius=r;
}
//?計算圓的周長
floatCircle::Circumference()const
{
return2*?PI?*?radius;
}
//?計算圓的面積
floatCircle::Area()const
{
returnPI?*?radius?*?radius;
}
voidmain()
{
floatradius;
floatFenceCost,?ConcreteCost;
//?提示用戶輸入半徑
cout<<"Enter?the?radius?of?the?pool:?";
cin>>radius;
//?聲明?Circle?對象
CirclePool(radius);
CirclePoolRim(radius?+3);
//計算柵欄造價并輸出
FenceCost=PoolRim.Circumference()*FencePrice;
cout<<"Fencing?Cost?is?¥"<
//計算過道造價并輸出
ConcreteCost=(PoolRim.Area()-
Pool.Area())*ConcretePrice;
cout<<"Concrete?Cost?is?¥"<
}
運行結果
Enter?the?radiusofthe?pool:10
Fencing?Costis¥2858.85
Concrete?Costis¥4335.39