版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
描述三維幾何模型
數(shù)據(jù):
點、線、面
幾何屬性(法向、曲率)
拓?fù)潢P(guān)系
…
操作:、保存數(shù)據(jù)
幾何操作
打光照
貼紋理
…描述學(xué)生
數(shù)據(jù):、
、
、籍貫、成績、
…
操作:
保存、導(dǎo)出數(shù)據(jù)
計算平均成績
…第六章
數(shù)據(jù)抽象------類與對象2012年12月Ps.
改編自陳家俊老師相關(guān)課件本章內(nèi)容
數(shù)據(jù)抽象與封裝
類和對象
對象的初始化和消亡前處理
常(const)成員
靜態(tài)(static)成員(friend)數(shù)據(jù)抽象與封裝
數(shù)據(jù)抽象
數(shù)據(jù)的使用者只需要知道對數(shù)據(jù)所能實施的操作以及這些操作之間的關(guān)系,而不必知道數(shù)據(jù)的具體表示。
數(shù)據(jù)封裝
指把數(shù)據(jù)及其操作作為一個整體來進(jìn)行描述。
數(shù)據(jù)的具體表示對使用者是不可見的,對數(shù)據(jù)的只能通過封裝體所提供的操作來完成。
數(shù)據(jù)抽象與封裝是面象程序設(shè)計的基礎(chǔ)與基本理念。例:“棧”數(shù)據(jù)的表示與操作進(jìn)棧(push):增加一個元素退棧(pop):刪除一個元素后進(jìn)先出!例:“?!睌?shù)據(jù)的表示與操作
棧(stack)是一種由若干個具有線性次序的元素所構(gòu)成的復(fù)合數(shù)據(jù)。對棧只能實施兩種操作:
進(jìn)棧(push):增加一個元素
退棧(pop):刪除一個元素
上述兩個操作必須在棧的同一端(稱為棧頂,top)進(jìn)行。
后進(jìn)先出(Last
In
Out,簡稱LIFO)是棧的一個重要性質(zhì)。
push(...);
...pop(...);
...
;
push(x);
pop(y);
x
==
y棧:top“?!睌?shù)據(jù)的表示與操作--非數(shù)據(jù)抽象和封裝途徑
定義棧數(shù)據(jù)類型const
int
STACK_SIZE=100;struct
Stack{ int
top/;/空棧top==-1;滿棧top==STACK_SIZE-1int
buffer[STACK_SIZE];};棧:top
直接操作棧數(shù)據(jù)Stack
st;//定義棧數(shù)據(jù) int
x;
//對st進(jìn)行初始化。st.top=-1;//把12放進(jìn)棧。
st.top++;st.buffer[st.top]
=
12;//把棧頂元素存入變量x并退棧。x=st.buffer[st.top];st.top--;
存在的問題?
必需知道數(shù)據(jù)的表示
數(shù)據(jù)表示發(fā)生變化將影響操作
不安全top棧:
通過過程抽象操作棧數(shù)據(jù)bool
push(Stack
&s,int
i)
//增加一個元素i至棧{ if
(s.top
==STACK_SIZE-1) {
cout
<<
“Stack
is
overflow.\n”;
return
false;}else{
s.top++;
s.buffer[s.top]
=
i;return
true;}}bool
pop(Stack
&s,int
&i)
//從棧退出一個元素,賦值給i{ if
(s.top
==
-1){
cout
<<“Stack
isempty.\n”;return
false;}else{
i=
s.buffer[s.top];
s.top--;return
true;}}void
init(Stack
&s)
//初始化棧{ s.top
=
-1;}Stack
st;//定義棧數(shù)據(jù)int
x;init(st);
//對st進(jìn)行初始化。push(st,
12);
//把12放進(jìn)棧。pop(st,
x);
//把棧頂元素退棧并存入變量x。
存在的問題?
數(shù)據(jù)類型的定義與操作的定義是分開的,二者之間沒有顯式的聯(lián)系,push、pop在形式上與一般的函數(shù),如void
f(Stack
&s),沒有區(qū)別:
數(shù)據(jù)表示仍然是公開的,可以不通過push、pop來操作st:
在數(shù)據(jù)表示上直接操作
通過函數(shù)f來操作產(chǎn)生動力歌曲,控制空調(diào)、燈…承載,接受發(fā)動力、產(chǎn)生運動…改變傳動比,變速、變扭和傳遞或切斷發(fā)
輸出的動力車身底盤變速箱行車電腦及中控系統(tǒng)......組成:發(fā)功能:汽車數(shù)據(jù)
操作“?!睌?shù)據(jù)的表示與操作--數(shù)據(jù)抽象和封裝途徑
定義棧數(shù)據(jù)類型const
int
STACK_SIZE=100;class
Stack{int
top;int
buffer[STACK_SIZE];public:Stack()
{
top
=
-1;
}bool
push(int
i);bool
pop(int
&i);};bool
Stack::push(int
i)
//增加一個元素i至棧{ if
(top
==
-1){ cout
<<
“Stack
is
empty.\n”;return
false;}else{ i
=
buffer[top];
top--;return
true;}}{ if(top==STACK_SIZE-1)//良好的編程!判斷操作有效性{ cout
<<
“Stack
is
overflow.\n”;
return
false;
}else{
top++; buffer[top]
=
i;return
true;}}bool
Stack::pop(int
&i)
//從棧退出一個元素,賦值給i//良好的編程
!判斷操作有效性
使用棧類型數(shù)據(jù)Stack
st; //會自動地去調(diào)用st.Stack()對st進(jìn)行初始化。
int
x;st.push(12); //把12放進(jìn)棧st。st.pop(x); //把棧頂元素退棧并存入變量x。st.top
=
-1;
//Error
!st.top++;
//Error
!st.buffer[st.top]
=
12;
//Error
!st.f();
//Error
!兩種方案的不同
在方案(1)中,數(shù)據(jù)的表示對數(shù)據(jù)的使用者是公開的,對棧的操作可以直接在棧的數(shù)據(jù)表示上進(jìn)行,也可以通過所提供的函數(shù)來實現(xiàn);而在方案(2)中,只能通過提供的函數(shù)來操作棧。
在方案(1)中,數(shù)據(jù)和對數(shù)據(jù)操作的描述相互獨立,數(shù)據(jù)是作為參數(shù)傳給對數(shù)據(jù)進(jìn)行操作的函數(shù);而在方案(2)中,數(shù)據(jù)和對數(shù)據(jù)的操作構(gòu)成了一個整體,數(shù)據(jù)操作是數(shù)據(jù)定義的一部分。
方案(1)需要顯式地對棧進(jìn)行初始化,方案(2)則是隱式地(自動)進(jìn)行初始化。類
對象構(gòu)成了面象程序的基本計算單位,而對象的特征則由相應(yīng)的類來描述。類是對象的集合。
C++的類是一種用戶自定義類型,定義形式如下:class
<類名>{<成員描述>};其中,類的成員包括:
數(shù)據(jù)成員
成員函數(shù)
類成員標(biāo)識符的作用域為整個類定義范圍例:一個日期類的定義class
Date
{
private:int
year,month,day;//數(shù)據(jù)成員public:void
set(int
y,int
m,int
d)//成員函數(shù){
year
=
y;month
=
m;day
=
d;}bool
is_leap_year()//成員函數(shù){ return
(year%4
==
0
&&
year%100
!=
0)
||(year%400==0);}void
print()//成員函數(shù){ cout
<<
year
<<
"."
<<
month
<<
"."
<<day;}};描述三維幾何模型
數(shù)據(jù):
點、線、面
幾何屬性(法向、曲率)
拓?fù)潢P(guān)系
…
操作:、保存數(shù)據(jù)
幾何操作
打光照
貼紋理
…描述三維幾何的網(wǎng)格類class
CMesh
{
public:CMesh();virtual
~CMesh();private:int//數(shù)據(jù)成員m_nTriangle;*m_Triangle;m_nVertex;*m_Vertex;*m_Vnormal;TriangleintCoord3Coord3…
…public://成員函數(shù)方法SaveData(FILE
*fp);ReadData(FILE
*fp);DrawModel(int
RenderMode,
int
RenderModel);V3Standarize(Vector3
v);voidintintvoid…
…};數(shù)據(jù)成員
數(shù)據(jù)成員指類的對象所包含的數(shù)據(jù),它們可以是常量和變量格式相同,例。數(shù)據(jù)成員的說明格式與非成員數(shù)據(jù)的如:class
Date//類定義{
......private:
//
控制說明int
year,month,day;
//數(shù)據(jù)成員說明};
說明數(shù)據(jù)成員時不允許進(jìn)行初始化(某些靜態(tài)數(shù)據(jù)成員除外)。例如:class
A{ int
x=0; //Error
!const
double
y=0.0;......//Error
!};
數(shù)據(jù)成員的類型可以是任意的C++類型(void除外)//A是在程序其它地方定義的類,這里是
。
在說明一個數(shù)據(jù)成員的類型時,如果未見到相應(yīng)的類
型定義或相應(yīng)的類型未定義完,則該數(shù)據(jù)成員的類型只能是這些類型的指針或 類型(靜態(tài)成員除外)。例如:class
A;class
B{ A
a;//Error,未見A的定義。
B
b;//Error,B還未定義完。A*p;
//OKB
*q;
//OKA
&aa;
//OKB
&bb;
//OK};成員函數(shù)
成員函數(shù)描述了對類定義中的數(shù)據(jù)成員所能實施的操作。
成員函數(shù)的定義可以放在類定義中,例如:class
A{
...void
f(){...}//建議編譯器按內(nèi)聯(lián)函數(shù)處理。};
成員函數(shù)的定義也可以放在類定義外,例如:class
A{
...void
f();
//};void
A::f(){...}//需要用類名受限,區(qū)別于全局函數(shù)。當(dāng)該類的代碼量(變量、函數(shù))很多時,一般采用第二種描述三維幾何的網(wǎng)格類//
Mesh.h class
CMesh
{public:CMesh();virtual
~CMesh();private:
//數(shù)據(jù)成員m_nTriangle;*m_Triangle;m_nVertex;*m_Vertex;*m_Vnormal;intTriangleintCoord3Coord3…
…public:
//
成員函數(shù)方法
函數(shù)void
SaveData(FILE*fp);int
ReadData(FILE
*fp);int
DrawModel(int
RenderMode,int
RenderModel);void
V3Standarize(Vector3
v);…
…};//
Mesh.cpp:
implementation
of
the
CMesh
class....
...CMesh::CMesh(){ ...
...
}
CMesh::~CMesh(){ ...
...}int
CMesh::ReadData(FILE
*fp)//函數(shù)實現(xiàn){int
i,j;float
box[2][3];float
center[3];for
(i=0;i<m_nVertex;i++){fscanf(fp,"%f%f%f",
&(m_Vertex[i][0]),
&(m_Vertex[i][1]),
&(m_Vertex[i][2]));m_pProgress->SetPos(i);}...
...return
m_nTriangle;}void
CMesh::SaveData(FILE
*fp)//函數(shù)實現(xiàn){int
i;fprintf(fp,"%d
%d\n",m_nsVertex,m_nsTriangle);...
...}
類成員函數(shù)名是可以重載的(析構(gòu)函數(shù)除外),它遵循一般函數(shù)名的重載規(guī)則。例如:class
A{
......public:void
f();int
f(int
i);double
f(double
d);......};類成員的
控制
在C++的類定義中,可以用
控制修飾符public,private或protected來描述對類成員的
限制。例如:class
A不受限制。{
public:
//int
x;void
f();private://只能在本類和
int
y;的代碼中。的代碼中。void
g();protected://只能在本類、派生類和
int
z;void
h();};
在C++的類定義中,默認(rèn)
控制是private,并可以有多個public、private和protected
控制說明,例如:class
A{ int
m,n;//m,n的public:int
x;void
f();private:int
y;void
g();protected:int
z;void
h();public:void
f1();控制說明為private。};
一般來說,類的數(shù)據(jù)成員和在類的的成員函數(shù)應(yīng)該指定為private,只有提供給外界使用的成員函數(shù)才指定為public。
具有public
控制的成員構(gòu)成了類與外界的一種接口(interface)。操作一個類的對象時,只能通過來實現(xiàn)。
protected類成員(繼承)。對象類中的public成員控制具有特殊的作用用鏈表實現(xiàn)“?!鳖怱tack#include
<iostream>#include
<cstdio>using
namespace
std;class
Stack{ public://對外的接口
Stack(){top=NULL;}
bool
push(int
i);bool
pop(int&
i);private:struct
Node{ int
content;}
*top;Node
*next;};//增加一個元素i至棧bool
Stack::push(int
i){Node
*p=new
Node;if
(p
==NULL)cout
<<
"Stack
isoverflow.\n";return
false;{}else{
p->content
=
i;p->next
=
top;return
true;top
=
p;}}bool
Stack::pop(int&
i)//從棧退出一個元素,賦值給i{ if
(top
==
NULL){ cout
<<
"Stack
isempty.\n";return
false;}{else
Node
*p=top;//i
=
top->content;top
=
top->next;
//
top
=
top->next;i
=
p->content;delete
p;
return
true;}}對
象
類屬于類型范疇的程序?qū)嶓w,它一般存在于靜態(tài)的程序(運行前的程序)中。
而動態(tài)的面
象程序(運行中的程序)則是由對象構(gòu)成。類是對象的抽象化,對象是類的具體化學(xué)生類:教師類:、、(對象)、路通
、 (對象)汽車類:大眾甲殼蟲、奧迪A6、寶馬X3(對象)點心類:面包、餅干、切糕(對象)對象在程序運行時創(chuàng)建,程序的執(zhí)行是通過對象之間相互發(fā)送消息來實現(xiàn)的。當(dāng)對象接收到一條消息后,它將調(diào)用對象類中定義的某個成員函數(shù)來處理這條消息。對象的創(chuàng)建和標(biāo)識
直接方式
通過在程序中定義一個類型為類的變量來實現(xiàn)的,其格式與普通變量的定義相同。例如:class
A{
public:void
f();void
g();private:int
x,y;}......A
a1;
//創(chuàng)建一個A類的對象。A
a2[100];//創(chuàng)建由對象數(shù)組表示的100個A類對象。
對象通過對象名來標(biāo)識和
。
分為:全局對象、局部對象和成員對象。
間接方式(動態(tài)對象)
在程序運行時刻,通過new操作或malloc庫函數(shù)來創(chuàng)建對象。
所創(chuàng)建的對象稱為動態(tài)對象,其內(nèi)存空間在程序的堆區(qū)中。
動態(tài)對象用delete操作或free庫函數(shù)來撤消(使之消亡)。
動態(tài)對象通過指針來標(biāo)識和
。單個動態(tài)對象的創(chuàng)建與撤消A
*p;p=new
A;
//創(chuàng)建一個A類的動態(tài)對象。動態(tài)對象……//通過pif
(p)delete
p;//撤消p所指向的動態(tài)對象?;騪
=
(A
*)malloc(sizeof(A));......free(p);動態(tài)對象數(shù)組的創(chuàng)建與撤消或p
=
(A
*)malloc(sizeof(A)*100);......free(p);A
*p;p=new
A[100];
//創(chuàng)建一個動態(tài)對象數(shù)組。......//通過pif
(p)delete
[]p;動態(tài)對象數(shù)組//撤消p所指向的動態(tài)對象數(shù)組。
對于動態(tài)對象,需注意下面幾點:
new操作自動分配空間、自動返回指定類型的指針。
用new創(chuàng)建的動態(tài)對象數(shù)組只能用默認(rèn)構(gòu)造函數(shù)進(jìn)行初始化。delete中的“[]”不能省,否則,只有第一個對象的析構(gòu)函數(shù)會被調(diào)用。
函數(shù)malloc不會調(diào)用對象類的構(gòu)造函數(shù);函數(shù)free也不會調(diào)對象類的析構(gòu)函數(shù)。后兩周課程及考試安排
本周五12月28號1-2節(jié)(郭)
本周五12月28日7-8節(jié)(郭)4:10-6:00其中5:00-5:30課堂測驗函數(shù)
本周六12月29號3-4節(jié)(郭,補(bǔ)下周三課)
下周一12月31日7-10節(jié)上機(jī)實驗
下周五1月4日1-2節(jié)習(xí)題課(劉)
下周五1月4日7-8節(jié)最后一次上機(jī)測驗
元月20號上午8:00-10:00:期末閉卷筆試產(chǎn)生動力歌曲,控制空調(diào)、燈…承載,接受發(fā)動力、產(chǎn)生運動…改變傳動比,變速、變扭和傳遞或切斷發(fā)
輸出的動力車身底盤變速箱行車電腦及中控系統(tǒng)......組成:發(fā)功能:汽車數(shù)據(jù)
操作描述三維幾何模型
數(shù)據(jù):
點、線、面
幾何屬性(法向、曲率)
拓?fù)潢P(guān)系
…
操作:、保存數(shù)據(jù)
幾何操作
打光照
貼紋理
…描述學(xué)生
數(shù)據(jù):、
、
、籍貫、成績、
…
操作:
保存、導(dǎo)出數(shù)據(jù)
計算平均成績
…類
對象構(gòu)成了面象程序的基本計算單位,而對象的特征則由相應(yīng)的類來描述。類是對象的集合。
C++的類是一種用戶自定義類型,定義形式如下:class
<類名>{<成員描述>};其中,類的成員包括:
數(shù)據(jù)成員
成員函數(shù)
類成員標(biāo)識符的作用域為整個類定義范圍數(shù)據(jù)成員
數(shù)據(jù)成員指類的對象所包含的數(shù)據(jù),它們可以是常量和變量格式相同,例。數(shù)據(jù)成員的說明格式與非成員數(shù)據(jù)的如:class
Date//類定義{
......private:
//
控制說明int
year,month,day;
//數(shù)據(jù)成員說明};
說明數(shù)據(jù)成員時不允許進(jìn)行初始化(某些靜態(tài)數(shù)據(jù)成員除外)。例如:class
A{ int
x=0; //Error
!const
double
y=0.0;......//Error
!};成員函數(shù)
成員函數(shù)描述了對類定義中的數(shù)據(jù)成員所能實施的操作。
成員函數(shù)的定義可以放在類定義中,例如:class
A{
...void
f(){...}//建議編譯器按內(nèi)聯(lián)函數(shù)處理。};
成員函數(shù)的定義也可以放在類定義外,例如:class
A{
...void
f();
//};void
A::f(){...}//需要用類名受限,區(qū)別于全局函數(shù)。當(dāng)該類的代碼量(變量、函數(shù))很多時,一般采用第二種例:一個日期類的定義class
Date
{
private:int
year,month,day;//數(shù)據(jù)成員public:void
set(int
y,int
m,int
d)//成員函數(shù){
year
=
y;month
=
m;day
=
d;}bool
is_leap_year()//成員函數(shù){ return
(year%4
==
0
&&
year%100
!=
0)
||(year%400==0);}void
print()//成員函數(shù){ cout
<<
year
<<
"."
<<
month
<<
"."
<<day;}};描述三維幾何的網(wǎng)格類//
Mesh.h class
CMesh
{public:
//
不受限制。CMesh();virtual
~CMesh();private:
//
數(shù)據(jù)成員
//只能在本類和
的代碼中
。m_nTriangle;*m_Triangle;m_nVertex;*m_Vertex;*m_Vnormal;intTriangleintCoord3Coord3…
…成員函數(shù)
方法
函數(shù)SaveData(FILE
*fp);ReadData(FILE
*fp);DrawModel(int
RenderMode,
int
RenderModel);V3Standarize(Vector3
v);…
…
//只能在本類、派生類和
的代碼中
。public:
//voidintintvoidprotected:};//
Mesh.cpp:
implementation
of
the
CMesh
class....
...CMesh::CMesh()
//構(gòu)造函數(shù){ ...
...
}
CMesh::~CMesh()
//析構(gòu)函數(shù){ ...
...}int
CMesh::ReadData(FILE
*fp)//函數(shù)定義{int
i,j;float
box[2][3];float
center[3];for
(i=0;i<m_nVertex;i++){fscanf(fp,"%f%f%f",
&(m_Vertex[i][0]),
&(m_Vertex[i][1]),
&(m_Vertex[i][2]));m_pProgress->SetPos(i);}...
...return
m_nTriangle;}void
CMesh::SaveData(FILE
*fp)//函數(shù)定義{int
i;fprintf(fp,"%d
%d\n",m_nsVertex,m_nsTriangle);...
...}VS
開發(fā)環(huán)境添加類對象的創(chuàng)建和標(biāo)識
class
A
{…
…};......//直接方式:A
a1;
//創(chuàng)建一個A類的對象。A
a2[100];//創(chuàng)建由對象數(shù)組表示的100個A。//間接方式:動態(tài)對象或動態(tài)對象數(shù)組A
*p=new
A;
//創(chuàng)建一個A類的動態(tài)對象。動態(tài)對象……//通過pif(p)delete
p;
//撤消p所指向的動態(tài)對象。對象的操作
對于創(chuàng)建的一個對象,需要通過向它發(fā)送消息來對它進(jìn)行操作(
象發(fā)送消息指:
調(diào)用對象類中定義的某個public成員函數(shù))。例如:class
A{ int
x;public:void
f();};int
main(){ A
a;a.f();//創(chuàng)建A類的一個局部對象a。//調(diào)用A類的成員函數(shù)f對對象a進(jìn)行操作。A
*p=new
A;
//創(chuàng)建A類的一個動態(tài)對象,p指向之。p->f();
//調(diào)用A類的成員函數(shù)f對p所指向的對象進(jìn)行操作。delete
p;return
0;}
通過對象來
類的成員時要受到類成員
控制的限制,例如::x,y,f,g,hclass
A{
public:void
f(){......//允許}private:int
x;void
g(){......//允許}protected:int
y;void
h();};:x,y,f,g,hvoid
A::h(){......//允許A
a;...//能}:x,y,f,g,ha.x、a.y、a.g和a.h嗎?void
func(){ A
a;a.f();
//OKa.x
=
1;
//Errora.g();
//Errora.y
=
1;
//Errora.h();
//Error......}
可以對同類對象進(jìn)行賦值Date
yesterday,
today,
some_day;some_day=yesterday;//把對象yesterday的數(shù)據(jù)成員分別
//賦值給對象some_day的相應(yīng)數(shù)據(jù)成員。
取對象地址Date
*p_date;p_date=&today;
//把對象today的地址賦值給對象指針p_date。
把對象作為實參傳給函數(shù)以及作為函數(shù)的返回值等操作Date
f(Date
d){ Date
x;......return
x;}some_day2=f(yesterday);//調(diào)用函數(shù)f,把對象yesterday//作為實參。返回值對象賦給對象some_day2。思考:直接進(jìn)行賦值有問題嗎?良好的編程
變量初始化(賦初值):初始化自定義變量是一種良好的編程
,是為了使程序更健壯,有助于減少Bugs的可能;使變量有一個可知的確定的值,如果沒有初始化會,當(dāng)程序執(zhí)行時可能出現(xiàn)未知或不可預(yù)料的錯誤。例如:int
nAge
=
0;char
cSex
=
'\0',
cMs
=
'\0';初始化一個數(shù)組或矩陣對象的初始化:構(gòu)造函數(shù)
當(dāng)一個對象被創(chuàng)建時,它將獲得一塊
空間,該
空間用于
對象的數(shù)據(jù)成員。
在使用對象前,需要對對象
空間中的數(shù)據(jù)成員進(jìn)行初始化。
C++提供了一種對象初始化的機(jī)制:構(gòu)造函數(shù)(Constructor)。
構(gòu)造函數(shù)是類的特殊成員函數(shù),它的名字與類名相同、無返回值類型。創(chuàng)建對象時,構(gòu)造函數(shù)會自動被調(diào)用。例如:
class
A{ int
x;public:A(){x=0;}//構(gòu)造函數(shù)......};......A
a;//創(chuàng)建對象a:為a分配內(nèi)存空間,然后調(diào)用a的構(gòu)造函數(shù)A()。
構(gòu)造函數(shù)可以重載,其中,不帶參數(shù)的(或所有參數(shù)都有默認(rèn)值的)構(gòu)造函數(shù)被稱為默認(rèn)構(gòu)造函數(shù)。例如:class
A{ int
x,y;public:A()//默認(rèn)構(gòu)造函數(shù){
x
=
y
=
0;}A(int
x1){ x
=
x1;
y
=
0;}A(int
x1,int
y1){ x
=x1;
y
=
y1;}......};如果類中未提供任何構(gòu)造函數(shù),則編譯程序在需要時會隱式地為之提供一個默認(rèn)構(gòu)造函數(shù)。
在創(chuàng)建對象時,可以顯式地指定調(diào)用對象類的某個構(gòu)造函數(shù)。
如果沒有指定調(diào)用何種構(gòu)造函數(shù),則調(diào)用默認(rèn)構(gòu)造函數(shù)初始化。class
A{
......
public:
A();A(int
i);A(char
*p);};......A
a1;//調(diào)用默認(rèn)構(gòu)造函數(shù)。也可寫成:A
a1=A();//但不能寫成:A
a1();A
a2(1);
//調(diào)用A(int
i)。也可寫成:A
a2=A(1);或A
a2=1;A
a3("abcd");//調(diào)A(char
*)。也可寫成:A
a3=A("abcd");//或A
a3="abcd";A
a[4];
//調(diào)用對象a[0]、a[1]、a[2]、a[3]的默認(rèn)構(gòu)造函數(shù)。class
A{
......
public:
A();A(int
i);A(char
*p);};......A
b[5]={A(),A(1),A("abcd"),2,"xyz"};//調(diào)用b[0]的A()、//b[1]的A(int)、b[2]的A(char
*)、b[3]的A(int)和b[4]的A(char
*)A
*p1=new
A;
//調(diào)用默認(rèn)構(gòu)造函數(shù)。A
*p2=new
A(2);//調(diào)用A(int
i)。A
*p3=new
A("xyz");
//調(diào)用A(char
*)。A
*p4=new
A[20];
//創(chuàng)建動態(tài)對象數(shù)組時只能調(diào)用各對象的//默認(rèn)構(gòu)造函數(shù)成員初始化表
對于常量數(shù)據(jù)成員和數(shù)據(jù)成員(某些靜態(tài)成員除外),不能在說明它們時初始化,也不能在構(gòu)造函數(shù)中采用賦值操作對它們初始化。例如:
class
A{ int
x;const
int
y=1;
//Error//Errorint
&z=x;public:A(){ x=
0;//OKy
=
1;
//Errorz
=
&x;
//Error}};
對于常量數(shù)據(jù)成員和數(shù)據(jù)成員,可以在定義構(gòu)造函數(shù)時,在函數(shù)頭和函數(shù)體之間加入一個成員初始化表來對它們進(jìn)行初始化。例如:class
A{ int
x;const
int
y;int&
z;public:A():z(x),y(1)
//成員初始化表{
x
=
0;}};
成員初始化表中成員初始化的書寫次序并不決定它們的初始化次序,數(shù)據(jù)成員的初始化次序由它們在類定義中的說明次序來決定。
在類中可以定義一個特殊的成員函數(shù):析構(gòu)函數(shù)
(Destructor),它的名字為“~<類名>”,沒有返回類型、不帶參數(shù)、不能被重載。例如:class
String{ int
len;char
*str;public:String(char*
s);~String();}
一個對象消亡時,系統(tǒng)在收回它的內(nèi)存空間之前,將會自動調(diào)用析構(gòu)函數(shù)。
可以在析構(gòu)函數(shù)中完成對象被刪除前的一些清理工作(如:歸還對象額外申請的資源等)。析構(gòu)函數(shù)–打掃戰(zhàn)場class
String{ int
len;char
*str;public:String(char*
s){ len
=
strlen(s);str=new
char[len+1];//申請資源strcpy(str,s);}~String(){
if
(str)delete[]str;//歸還資源}};void
f(){
String
s1("abcd");//調(diào)用s1的構(gòu)造函數(shù)......}//調(diào)用s1的析構(gòu)函數(shù)
注意:系統(tǒng)為對象s1分配的內(nèi)存空間只包含len和str(指針)本身所需的空間,str所指向的空間不由系統(tǒng)分配,而是由對象
(new)自己處理!s1len:str:4abcd
析構(gòu)函數(shù)可以顯式調(diào)用s1.~String();
//只歸還對象的資源,//對象并未消亡!成員對象
對于類的數(shù)據(jù)成員,其類型可以是另一個類。也就是說,一個對象可以包含另一個對象(稱為成員對象)。例如:class
A{
...};class
B{...A
a;//成員對象...};B
b;//對象b包含一個成員對象:b.a成員對象的初始化
成員對象由成員對象類的構(gòu)造函數(shù)初始化:
如果在包含成員對象的類中,沒有
用成員對象類的什么構(gòu)造函數(shù)對成員對象初始化,則調(diào)用成員對象類的默認(rèn)構(gòu)造函數(shù)。
可以在類構(gòu)造函數(shù)的成員初始化表中顯式
用成員對象類的某個構(gòu)造函數(shù)對成員對象初始化。class
A{ int
x;public:A(){
x
=
0;
}A(int
i)
{
x
=
i;
}};class
B{ Aa;int
y;public:B(int
i){y=i;}//調(diào)用A的默認(rèn)構(gòu)造函數(shù)對a初始化。
B(int
i,
intj):a(j){y=i;}//調(diào)用A(int)對a
初始化。};B
b1(1);//b1.y初始化為1,b1.a.x初始化為0B
b2(1,2);//b2.y初始化為1,b2.a.x初始化為2
創(chuàng)建包含成員對象的類的對象時,先執(zhí)行成員對象類的構(gòu)造函數(shù),再執(zhí)行本身類的構(gòu)造函數(shù)。
一個類若包含多個成員對象,這些對象的初始化次序按它們在類中的說明次序(而不是成員初始化表的次序)進(jìn)行。
析構(gòu)函數(shù)的執(zhí)行次序與構(gòu)造函數(shù)的執(zhí)行次序正好相反??截悩?gòu)造函數(shù)
在創(chuàng)建一個對象時,若用一個同類型的對象對其初始化,這時將會調(diào)用一個特殊的構(gòu)造函數(shù):拷貝構(gòu)造函數(shù)。例如:class
A{
......public:A();
//默認(rèn)構(gòu)造函數(shù)A(const
A&
a);
//拷貝構(gòu)造函數(shù)};
在三種情況下,會調(diào)用類的拷貝構(gòu)造函數(shù):
定義對象時,例如:A
a1;A
a2(a1);
//也可寫成:A
a2=a1;或:A
a2=A(a1);//調(diào)用A的拷貝構(gòu)造函數(shù),用對象a1初始化對象a2,
把對象作為值參數(shù)傳給函數(shù)時,例如:void
f(A
x);A
a;f(a);//調(diào)用f時將創(chuàng)建形參對象x,并調(diào)用A的拷貝構(gòu)造函數(shù),//用對象a對其初始化。
把對象作為函數(shù)的返回值時,例如:A
f(){ A
a;......return
a;//創(chuàng)建一個A類的臨時對象,并調(diào)用A的//拷貝構(gòu)造函數(shù),用對象a對其初始化。}隱式拷貝構(gòu)造函數(shù)
如果程序中沒有為類提供拷貝構(gòu)造函數(shù),則編譯器將會為其生成一個隱式拷貝構(gòu)造函數(shù)。
隱式拷貝構(gòu)造函數(shù)將逐個成員拷貝初始化:
對于普通成員:它采用通常的初始化操作;
對于成員對象:則調(diào)用成員對象類的拷貝構(gòu)造函數(shù)來實現(xiàn)成員對象的初始化。class
A{ int
x,
y;public:A()
{x=0; y=2;
}void
inc(){
x++;y++;}......//其中沒有定義拷貝構(gòu)造函數(shù)。};A
a1;a1.inc();A
a2(a1);//a2.x初始化為1(a1.x);//a2.y初始化為3(a1.y)class
A{ int
x,y;public: A()
{
x
=
y
=
0;
}
......};class
B{ int
z;A
a;public:B()
{
z
=
0;
}......//其中沒有定義拷貝構(gòu)造函數(shù)};...B
b1;B
b2(b1);//b1.z、b1.a.x以及b1.a.y均為0。//b2.z初始化成b1.z;調(diào)用A的拷貝構(gòu)造函數(shù)用b1.a對//b2.a初始化。如果A中沒有定義拷貝構(gòu)造函數(shù),則//A的隱式拷貝構(gòu)造函數(shù)把b2.a.x和b2.a.y分別初始化成//b1.a.x和b1.a.y;否則,由A的自定義拷貝構(gòu)造函數(shù)決定//如何對b2.a.x和b2.a.y進(jìn)行初始化。自定義拷貝構(gòu)造函數(shù)
一般情況下,編譯程序提供的默認(rèn)拷貝構(gòu)造函數(shù)的行為足以滿足要求,類中不需要自定義拷貝構(gòu)造函數(shù)。在有些情況下必須要自定義拷貝構(gòu)造函數(shù),否則,將會產(chǎn)生設(shè)計者未
的嚴(yán)重的程序錯誤。class
A{ int
x,y;char
*p;
public:
A(char
*str){ x
=
0; y
=
0;p
=
new
char[strlen(str)+1];strcpy(p,str);}};xypxyp~A()
{
delete[]
p;
p=NULL;
}a1a2abcd0000......A
a1(“abcd”);A
a2(a1);系統(tǒng)提供的隱式拷貝構(gòu)造函數(shù)將會使得a1和a2的成員指針p指向同一塊內(nèi)存區(qū)域!
它帶來的問題是:
如果對一個對象操作之后修改了這塊空間的內(nèi)容,則另一個對象將會受到影響。如果不是設(shè)計者特意所為,這將是一個隱藏的錯誤。
當(dāng)對象a1和a2消亡時,將會分別去調(diào)用它們的析構(gòu)函數(shù),這會使得同一塊內(nèi)存區(qū)域?qū)⒈粴w還兩次,從而導(dǎo)致程序運行異常。
解決上面問題的辦法是在類A中顯式定義一個拷貝構(gòu)造函數(shù)A::A(const
A&
a){ x
=
a.x;y
=a.y;p
=
new
char[strlen(a.p)+1];strcpy(p,a.p);}xypxypa1a2abcd0000abcd再回顧關(guān)于結(jié)構(gòu)體變量的賦值struct
Vect{int
n;int
*p;}A;cin>>A.n;該程序有問題嗎?B.p=A.p;B.p=new
int[B.n];for
(int
i=0;i<A.n;
i++)B.p[i]
=A.p[i];函數(shù)A.p=new
int[A.n/]/;以上可以寫成個…
…//
Vect
B=A;if
(A.p)delete
[]A.p;if
(B.p)delete
[]B.p;
自定義拷貝構(gòu)造函數(shù)可以對初始化的行為進(jìn)行控制。例如:class
A{ int
x,y;public:A()
{
x
=
0; y
=
2;}A(const
A&
a){ x
=
a.x+1;y
=
a.y+1;}};......A
a1;
//a1初始化為:a1.x=0,a1.y=2A
a2(a1);//a2初始化為:a2.x=1,a2.y=3
自定義的拷貝構(gòu)造函數(shù)將默認(rèn)調(diào)用成員對象類的默認(rèn)構(gòu)造函數(shù)對成員對象初始化!class
A{ int
x,y;public:A()
{
x
=
0; y
=
2;}void
inc()
{
x++;
y++;
}};{
z
=
b.z;
}B
b1;B
b2(b1)
如何能讓b2與b1一致呢?class
B{ intz;A
a;public:B()
{z
=
0;
}B(const
B&
b):
a(b.a)void
inc()
{z++;a.inc();
}};...//b1.a.x為0、b1.a.y為2、b1.z為0
。b1.inc();
//b1.a.x為1、b1.a.y為3、b1.z為1。//b2.a.x為1、b2.a.y為3、b2.z為1。const成員函數(shù)
在程序運行的不同時刻,一個對象可能會處于不同的狀態(tài)(由對象的數(shù)據(jù)成員的值來體現(xiàn))。
可以把類中的成員函數(shù)分成兩類:
獲取對象狀態(tài)
改變對象狀態(tài)例如class
Date{
public:void
set(int
y,
int
m,
int
d)//改變對象狀態(tài)
int
get_day();//獲取對象狀態(tài)int
get_month();//獲取對象狀態(tài)
int
get_year();//獲取對象狀態(tài)......};
為了防止在獲取對象狀態(tài)的成員函數(shù)中改變對象的狀態(tài),
可以把它們說明成const成員函數(shù)。
const成員函數(shù)不能改變對象的狀態(tài)(數(shù)據(jù)成員的值)。例如:class
A{ int
x;char
*p;public:......void
f()
const{ x
=
10;
//Errorp
=
new
char[20];
//Errorstrcpy(p,"ABCD");//沒有改變p的值,編譯程序認(rèn)為OK!}};
const修飾符還有一個作用:修飾常量對象,限制對常量對象的操作。例如:class
Date{ int
d,m,y;public:Date();Date(int
year,
int
month,
int
day);int
get_day()
const
{
return
d;
}int
get_month()
const
{
return
m;
}int
get_year()
const
{
return
y;
}int
set
(int
year,
int
month,
int
day){ y
=
year;
m
=
month;
d
=
day;}};void
f(const
Date
&d){
cout
<<d.get_day()
<<
d.get_month()
<<
d.get_year();d.set
(2011,3,23);
//Error}同類對象共享數(shù)據(jù)
屬于同一個類的不同對象有時需要共享數(shù)據(jù)。
采用全局變量來表示共享數(shù)據(jù)違背數(shù)據(jù)抽象與封裝原則,數(shù)據(jù)缺乏保護(hù)。int
x;//被A類對象共享的全局變量class
A{
......{
x++;
......
}void
f()}
a,b;a.f();b.f();//上述操作對同一個x進(jìn)行x++;
//不通過A類對象也能
x!回顧:舉例關(guān)于staticvoid
f(){
auto
int
x=0;//auto一般不寫
static
inty=1;register
int
z=0;x++;
y++;z++;cout
<<
x
<<
y
<<
z
<<
endl;}//在main函數(shù)中調(diào)用f();
第一次調(diào)用f時,輸出:1
2
1
第二次調(diào)用f時,輸出:1
3
1
可通過靜態(tài)數(shù)據(jù)成員來實現(xiàn)屬于同一個類的不同對象之間的數(shù)據(jù)共享:class
A{
......static
int
x;//靜態(tài)數(shù)據(jù)成員{
x++;......
}void
f()}
a,b;a.f();b.f();//上述操作對同一個x進(jìn)行x++;
//Error,不通過A類對象不能
x!
在類中,可以把數(shù)據(jù)成員說明成靜態(tài)的。例如:class
A{ int
x,y;static
intshared;
//靜態(tài)數(shù)據(jù)成員說明
public:A()
{
x
=
y
=
0;}void
increase_all()
{
x++;
y++;
shared++;
}int
sum_all()
const
{
return
x+y+shared;
}......};int
A::shared=0;
//靜態(tài)數(shù)據(jù)成員的定義靜態(tài)數(shù)據(jù)成員
類的靜態(tài)數(shù)據(jù)成員對該類的所有對象只有一個拷貝。例如:A
a1,a2;shared:
0a1a2a1.x:a1.y:00a2.x:a2.y:
00
類的靜態(tài)數(shù)據(jù)成員對該類的所有對象只有一個拷貝。例如:A
a1,a2;shared:
1a1a20a1.x:
a2.x:a1.y:11a2.y:
0a1.increase_all();cout<<a2.sum_all()<<endl;
//輸出:1靜態(tài)成員函數(shù)
成員函數(shù)也可以
成靜態(tài)的。class
A{ int
x,y;static
int
shared;public:A()
{
x
=
y
=
0;
}static
int
get_shared()
{
return
shared;
}......};int
A::shared=0;
靜態(tài)成員函數(shù)只能類的靜態(tài)成員。
靜態(tài)成員函數(shù)可以通過對象來
外,也可以直接通過類來
。例如:A
a;cout<<a.get_shared();//也可以是:A::get_shared();
classA
{
static
int
obj_count;…...public:A()
{obj_count++;}~A()
{
obj_count--;
}static
int
get_num_of_objects(){
return
obj_count;}…...};int
A::obj_count=0;......cout
<<
A::get_num_of_objects()
<<
endl;例:實現(xiàn)對某類對象的計數(shù)類成員的
控制
在類定義中,用
控制修飾符public,private,protected來描述對類成員的
限制。
例如:class
A{
public:
//int
x;void
f();不受限制。的代碼中private://只能在本類和
int
y;void
g();。的代碼中protected://只能在本類、派生類和
int
z;void
h();。};某些全局函數(shù)某些其它類某些其它類的某......class
A類成員函數(shù){
......friend
void
func();
//
函數(shù)friend
class
B;
//
類friend
void
C::f();
//些成員函數(shù)};
為了提高在類的外部對類的數(shù)據(jù)成員的
效率,在C++中,可以指定與一個類密切相關(guān)的、又不適合作為該類成員的程序?qū)嶓w可以直接 該類的private和protected成員,這些程序?qū)嶓w稱為該類的 。例如:所謂外地,就是作為一個類的“朋友”,可以例它的私有成員數(shù)據(jù)或私有成員函數(shù)。關(guān)于
的幾點說明是數(shù)據(jù)保護(hù)和數(shù)據(jù)
效率之間的一種折衷方案。關(guān)系具有不對稱性。例如:假設(shè)B是A的,如果沒有顯式A是B的,則A不是B的。也不具有傳遞性。例如:假設(shè)B是A的、C是B的
,如果沒有顯式
C是A的
,則C不是A的
。類應(yīng)用舉例用類來實現(xiàn)矩陣和向量類型定義:矩陣類、向量類數(shù)據(jù):行數(shù)、列數(shù)、數(shù)據(jù)……具體操作:矩陣、向量的元素實現(xiàn)乘法……例:用類來實現(xiàn)矩陣和向量類型class
Matrix
//矩陣類{ int
*p_data; //表示矩陣數(shù)據(jù)int
row,col; //表示矩陣的行數(shù)和列數(shù)
public:Matrix(int
r,
int
c){ if
(r
<=
0
||
c
<=
0){ cerr<<"矩陣尺寸不合法!\n";exit(-1);}row
=
r; col
=
c;p_data
=
new
int[row*col];for
(int
i=0;
i<row*col;
i++)
p_data[i]
=
0;}~Matrix(){delete
[]p_data;}int
&element(int
i,
int
j)
//矩陣元素。{ if
(i
<
0
||
i
>=
row
||
j
<
0
||
j
>=
col){ cerr<<"矩陣下標(biāo)越界\n";exit(-1);}return
*(p_data+i*col+j);}in ement(int
i,
int
j)
const//
矩陣元素(為常量對象而提供)。{ if
(i
<
0
||i
>=
row
||
j
<
0
||
j
>=
col){ cerr<<"矩陣下標(biāo)越界\n";exit(-1);}return
*(p_data+i*col+j);}Matrix
m(10,10);......m.element(1,2)
=m.element(1,2)+1;void
f(const
Matrix&
m){
int
x;x
=m.element(1,2)*10+1;}int
dimension_row()const//獲得矩陣的行數(shù)。{ return
row;
}
int
dimens
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 成語故事-此地?zé)o銀三百兩-課件
- 相交弦定理課件
- 清兵衛(wèi)與葫蘆-課件2
- 《酸堿中和滴定》課件
- 單位人力資源管理制度品讀選集十篇
- 2024年市場推廣方案
- 【課件】配置遠(yuǎn)程訪問服務(wù)
- 單位管理制度展示合集員工管理
- 單位管理制度展示大全人事管理十篇
- 單位管理制度收錄大全人事管理篇十篇
- 五年級數(shù)學(xué)試卷分析
- 皮下注射抗凝劑相關(guān)知識試題
- 沛縣生活垃圾焚燒發(fā)電項目二期工程 環(huán)境影響報告書 報批稿
- DB44∕T 2149-2018 森林資源規(guī)劃設(shè)計調(diào)查技術(shù)規(guī)程
- 肝移植的歷史、現(xiàn)狀與展望
- 商業(yè)定價表(含各商鋪價格測算銷售回款)
- 【化學(xué)】重慶市2021-2022學(xué)年高一上學(xué)期期末聯(lián)合檢測試題
- 單位工程質(zhì)量控制程序流程圖
- 部編版小學(xué)語文三年級(下冊)學(xué)期課程綱要
- 化學(xué)工業(yè)有毒有害作業(yè)工種范圍表
- 洼田飲水試驗
評論
0/150
提交評論