C++程序設(shè)計(jì)教程課件_第1頁
C++程序設(shè)計(jì)教程課件_第2頁
C++程序設(shè)計(jì)教程課件_第3頁
C++程序設(shè)計(jì)教程課件_第4頁
C++程序設(shè)計(jì)教程課件_第5頁
已閱讀5頁,還剩47頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

C++程序設(shè)計(jì)教程(第二版)9/19/20231第九章 對(duì)象生滅第九章內(nèi)容9/19/20232構(gòu)造函數(shù)設(shè)計(jì)構(gòu)造函數(shù)的重載類成員初始化構(gòu)造順序拷貝構(gòu)造函數(shù)析構(gòu)函數(shù)對(duì)象轉(zhuǎn)型與賦值1.構(gòu)造函數(shù)設(shè)計(jì)9/19/20233

初始化要求定義一個(gè)對(duì)象,其形式與定義一個(gè)變量相似,但更具意義。對(duì)象與變量的不同在于對(duì)象對(duì)應(yīng)于事物,要求從誕生之時(shí)起便有明確的意義.對(duì)象必須建立一種初始化機(jī)制,以滿足在編程中可以針對(duì)實(shí)際問題所提出的要求而賦給一個(gè)有意義的初值。創(chuàng)建一個(gè)對(duì)象,若創(chuàng)建的是全局對(duì)象,則以全0的模式表示對(duì)象,若創(chuàng)建局部對(duì)象,則以隨機(jī)值表示對(duì)象。對(duì)象的初始化不是簡單的參數(shù)與成員對(duì)應(yīng),而是聯(lián)系參數(shù)到成員的過程.封裝性要求Struct

Point{int

x,y;};Point

d={2,3};class

Point{int

x,y;//…};Point

d={2,3};正確錯(cuò)誤封裝性的要求杜絕了這種初始化形式,事實(shí)上,這種形式根本不能完成對(duì)象的初始化過程中的校驗(yàn)和計(jì)算工作。對(duì)象通常是一個(gè)復(fù)雜的實(shí)體,在構(gòu)建對(duì)象過程中,并不一定是一個(gè)初值對(duì)應(yīng)一個(gè)對(duì)象分量。許多時(shí)候,一個(gè)初值只是傳遞一個(gè)信息,告訴對(duì)象的創(chuàng)建工作應(yīng)怎么進(jìn)行。封裝性要求對(duì)象創(chuàng)建中按傳遞的信息進(jìn)10/行1/20一23

個(gè)過程化的初始化工作。4

函數(shù)形式構(gòu)造函數(shù)(constructor)是與類名同名的特殊的成員函數(shù),當(dāng)定義該類的對(duì)象時(shí),構(gòu)造函數(shù)將被自動(dòng)調(diào)用以實(shí)現(xiàn)對(duì)該對(duì)象的初始化。構(gòu)造函數(shù)不能有返回值,因而不能指定包括void在內(nèi)的任何返回值類型。構(gòu)造函數(shù)的定義體可與其它成員函數(shù)成員一樣,放在類內(nèi)或類外都可。構(gòu)造函數(shù)的定義格式為:類名(形參說明){函數(shù)體}構(gòu)造函數(shù)既可定義成有參函數(shù),也可義成無參函數(shù),要根據(jù)問題的需要來定。全局變量和靜態(tài)變量在定義時(shí),將自動(dòng)賦初值為0;局部變量在定義時(shí),其初始值不固定的。而當(dāng)對(duì)象被定義時(shí),由于對(duì)象的意義表達(dá)了現(xiàn)實(shí)世界的實(shí)體,所以一旦定義對(duì)象,就必須有一個(gè)有意義的初始值,在C++中,在定義對(duì)象的同時(shí),給該對(duì)象初始化的方法就是利用構(gòu)造函數(shù)。10/1/20235例:類person包括4個(gè)數(shù)據(jù)成員,用來記錄人員信息。生成對(duì)象obj,并使用構(gòu)造函數(shù)為obj賦予初始值。#

include<windows.h>#

include<iostream.h>class

Person{

private:char

name

[10]

;int

age

;int

salary

;chartel[8];public://定義類//類Person的數(shù)據(jù)成員//姓名//年齡//薪金//電話//構(gòu)造函數(shù)PersonPerson

(

char

*xname,

int

xage,int

xsalary,

char

*xtel

)

;void

disp

();

};//函數(shù)Person的定義Person

::

Person

(

char

*xname,int

xage,

int

xsalary,

char

*xtel

){strcpy

(name,xname);//給各數(shù)據(jù)成員提供初值

age=xage;salary

=

xsalary

;10/1s/t2r0c2p3y

(tel,

xtel)

;}6//函數(shù)disp的定義

void

Person::disp(){

cout<<endl;10/1/20237姓名:"<<name<<endl;年齡:"<<age<<endl;

工資:"<<salary<<endl;電話:"<<tel<<endl<<endl;}cout

<<

"cout

<<

"cout

<<

"cout

<<

"http://主函數(shù)void

main(

){

//生成對(duì)象obj并初始化Person obj("張立三",25,850,"45672314");//顯示objobj.disp();}程序的執(zhí)行結(jié)果是:姓名:張立三年齡:25工資:850電話:45672314在主函數(shù)中的Person

obj("張立三",25,850,"45672314");中完成了以下幾個(gè)功能:定義并生成了對(duì)象obj。在生成對(duì)象obj的同時(shí),自動(dòng)調(diào)用相應(yīng)類的構(gòu)造函數(shù)Person將初始值"張立三",25,850,"45672314"傳遞給構(gòu)造函數(shù)Person相應(yīng)的形參xname,xage,xsalary,

xtel。執(zhí)行構(gòu)造函數(shù)體,將相應(yīng)的值賦給相應(yīng)的數(shù)據(jù)成員。10/1/20238

一次性對(duì)象10/1/20239創(chuàng)建對(duì)象時(shí)如果不給出對(duì)象名,直接以類名調(diào)用構(gòu)造函數(shù),則產(chǎn)生一個(gè)無名對(duì)象。無名對(duì)象經(jīng)常在參數(shù)傳遞時(shí)使用。例如:cout<<Date(2003,12,23);Date(2003,12,23)是一個(gè)對(duì)象,該對(duì)象在做了<<操作后便煙消云散了,所以這種對(duì)象一般用在創(chuàng)建后不需要反復(fù)使用的場(chǎng)合。2.構(gòu)造函數(shù)重載10/1/202310class

Date{public:Date(const

string&

s);//重載//

...};構(gòu)造函數(shù)畢竟是函數(shù),是函數(shù)就可以重載。不但可以重載,還可以設(shè)置默認(rèn)參數(shù)。如果一個(gè)類中出現(xiàn)了兩個(gè)以上的同名的成員函數(shù)時(shí),稱為類的成員函數(shù)的重載。intmain(){Date

d(“2006-12-26”);Date

e(2000,

12,

25);Date

f(2001,

10);Date(int

y=2003,

int

m=12,

int

d=1);//參數(shù)默認(rèn)Dateg(2002);Date

h;//

...}Date

h;這行代碼似乎是一個(gè)錯(cuò)誤,對(duì)于對(duì)象的創(chuàng)建,即對(duì)于無參的構(gòu)造函數(shù)的調(diào)用,應(yīng)該是g(),加上類名,即寫成:

Dateg();但是,從語法上來講,這個(gè)語句也是名叫g(shù)的返回臨時(shí)Date對(duì)象的函數(shù)聲明!因此,C++語言在設(shè)計(jì)時(shí),為了區(qū)別無初始化的對(duì)象定義和返回類對(duì)象的無參函數(shù)聲明的差別,也為了保持無初始化變量定義與無初始化(無參)對(duì)象定義的一致性,規(guī)定無參對(duì)象定義語句為:10/1/202311int

a;int

b;Date

g;Dateg();//變量定義//返回整型值的無參函數(shù)聲明//無參對(duì)象定義,加空括號(hào)后就成了無參函數(shù)聲明//返回類對(duì)象的無參函數(shù)聲明對(duì)于返回對(duì)象值的有參函數(shù)聲明和有初始化的對(duì)象定義語句,由于函數(shù)聲明中的參數(shù)有類型引導(dǎo),而對(duì)象定義的初始化中無類型引導(dǎo),它們本身(或在編譯器看來)是可以區(qū)分的:10/1/202312Date

e(2002);Date e(int

y);//對(duì)象定義//函數(shù)聲明C++規(guī)定,每個(gè)類必須有一個(gè)構(gòu)造函數(shù)。如果在類中沒有顯式定義構(gòu)造函數(shù)時(shí),則C++編譯系統(tǒng)在編譯時(shí)為該類提供一個(gè)默認(rèn)的構(gòu)造函數(shù),該默認(rèn)構(gòu)造函數(shù)是個(gè)無參函數(shù),它僅負(fù)責(zé)創(chuàng)建對(duì)象,而不做任何初始化工作。class

Date{public://相當(dāng)于定義了Date(){}};intmain(){Date

d;

//

ok//

...}與變量定義相似,在用默認(rèn)構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),如果創(chuàng)建的是全局對(duì)象或靜態(tài)對(duì)象,則對(duì)象的默認(rèn)值為0,否則對(duì)象的初始值是不定的。10/1/202313只要一個(gè)類定義了一個(gè)構(gòu)造函數(shù)(不一定是無參構(gòu)造函數(shù)),C++編譯系統(tǒng)就不再提供默認(rèn)的構(gòu)造函數(shù)。任何其他的構(gòu)造函數(shù)定義,都將阻止默認(rèn)無參空函數(shù)的產(chǎn)生:class

Date{public:Date(int

y,

int

m,

int

d){}//

...};int

main(){Date

d;

//

error//

...}10/1/202314當(dāng)構(gòu)造函數(shù)有缺省參數(shù)時(shí),稱為具有缺省參數(shù)的構(gòu)造函數(shù),在使用時(shí)要防止二義性。10/1/202315//定義類Myclass//構(gòu)造函數(shù)Myclass如:class

Myclass{

private:intmember;public:Myclass();Myclass(int

i);……}Myclass:Myclass(){

member=10;

}Myclass:Myclass(int

i=10)//構(gòu)造函數(shù)Myclass(int

i),該函數(shù)//的形參i為缺省參數(shù){

member=i;

}void

main(){

Myclass

x(20);10/1/202316Myclass

y;//產(chǎn)生二義性,無法確定自動(dòng)調(diào)用哪個(gè)構(gòu)造//函數(shù)完成對(duì)象的構(gòu)造……}回顧:上節(jié)課主要講了構(gòu)造函數(shù)的概念、意義及定義方式、構(gòu)造函數(shù)的重載。10/1/2023173.類成員初始化10/1/202318

默認(rèn)調(diào)用的無參構(gòu)造函數(shù)在類定義中有數(shù)據(jù)成員和成員函數(shù),數(shù)據(jù)成員可以是內(nèi)部數(shù)據(jù)類型的變量實(shí)體,也可以是對(duì)象實(shí)體。如果一個(gè)類A的對(duì)象作為另一個(gè)類B的數(shù)據(jù)成員,則在類B的對(duì)象創(chuàng)建過程中,調(diào)用其構(gòu)造函數(shù)的過程中,數(shù)據(jù)成員(類A的對(duì)象)會(huì)自動(dòng)調(diào)用類A的構(gòu)造函數(shù)。這樣就會(huì)面臨一些問題。例:有一個(gè)學(xué)號(hào)類和一個(gè)學(xué)生類,學(xué)生類中包含了學(xué)號(hào)類的對(duì)象,因此在構(gòu)造學(xué)生類對(duì)象時(shí),面臨著學(xué)號(hào)類對(duì)象的構(gòu)造。class

StudentID{int

value;

public:StudentID(){在學(xué)生類的構(gòu)造函數(shù)中并沒有看到學(xué)號(hào)類對(duì)象初始化的痕跡,而數(shù)據(jù)成員name倒被賦了初值。從運(yùn)行的結(jié)果看,當(dāng)學(xué)生類對(duì)象被構(gòu)造時(shí),一個(gè)學(xué)號(hào)對(duì)象也創(chuàng)建了,而且學(xué)號(hào)類的構(gòu)造函數(shù)先于學(xué)生類對(duì)象的構(gòu)造函數(shù)體的執(zhí)行而執(zhí)行。static

int

nextStudentID

=

0;value

=

++nextStudentID;cout<<"Assigning

student

id"<<value<<"\n";}};//-----------------------------------class

Student{string

name;StudentID

id;public:Student(string

n

=

"noName"){cout

<<"Constructing

student

"

+

n

+

"\n";name

=

n;}};//-----------------------------------int

main(){S1tu0/d1/2e0n23t

s("Randy");}//==============================19對(duì)于Student

s(“Randy”);其內(nèi)部的執(zhí)行順序是這樣的:先分配學(xué)生類對(duì)象s的空間,調(diào)用Student構(gòu)造函數(shù);在Student構(gòu)造函數(shù)體尚未執(zhí)行時(shí),由于看到了類的對(duì)象成員ID,轉(zhuǎn)而去調(diào)用學(xué)號(hào)類的無參構(gòu)造函數(shù);相當(dāng)于執(zhí)行定義語句:StudentID

id;執(zhí)行了學(xué)號(hào)類構(gòu)造函數(shù)體,輸出結(jié)果的第1行信息,返回到Student構(gòu)造函數(shù);執(zhí)行Student構(gòu)造函數(shù)體,輸出結(jié)果的第2行信息,完成全部構(gòu)造工作。說明:先成員構(gòu)造,后自身構(gòu)造.成員構(gòu)造不見顯式調(diào)用,而是悄悄調(diào)用無參構(gòu)造函數(shù).對(duì)學(xué)號(hào)類構(gòu)造函數(shù)的調(diào)用時(shí)

默認(rèn)的,默認(rèn)調(diào)用便是調(diào)用無參構(gòu)造函數(shù),而正好學(xué)號(hào)類

設(shè)計(jì)的構(gòu)造函數(shù)就是無參構(gòu)造函數(shù)。10/1/202320

初始化的困惑在剛剛的實(shí)例中,只是初始化了名稱,而沒有給定學(xué)號(hào)。如果,在學(xué)生對(duì)象創(chuàng)建中,既要初始化名稱,又要給定一個(gè)指定的初始化學(xué)號(hào),也就是不要默認(rèn)調(diào)用無參構(gòu)造函數(shù),那么類該如何操作呢?如果不能在創(chuàng)建StudentID的過程中初始化對(duì)象,就不能將對(duì)象值設(shè)置到位。下面給出一個(gè)不正確的初始化嘗試,還是對(duì)剛才的例子作修改:10/1/202321class

StudentID{intvalue;public:StudentID(int

id=0){value

=

id;cout<<"Assigning

student

id

"<<value<<"\n";}};//class

Student{string

name;StudentID

id;public:Student(string

n

=

"noName",

int

ssID=0){cout

<<"Constructing

student

"

+

n

+"\n";name

=

n;StudentID

id(ssID);}};//運(yùn)行結(jié)果:intmain(){Student

s("Randy",58);10/1/2}0/2/3====================================22S對(duì)象初始化的學(xué)號(hào)為58,重新設(shè)計(jì)了Student構(gòu)造函

數(shù),將該值傳遞給了它,所以形參ssID的值也為58。但是我們看到轉(zhuǎn)而調(diào)用的StudentID構(gòu)造函數(shù)執(zhí)行體卻沒有輸出58,而是默認(rèn)的0學(xué)號(hào)。這說明轉(zhuǎn)而調(diào)用的仍然是無參構(gòu)造函數(shù)。將StudentID的構(gòu)造函數(shù)寫成參數(shù)默認(rèn)是為了讓無參構(gòu)造函

數(shù)調(diào)用也能通過,以便讓整個(gè)程序順利運(yùn)行。乃至后來,要想在Student類內(nèi),通過構(gòu)造函數(shù)體中的對(duì)象初始化創(chuàng)建的定義語句來改變id的值,發(fā)現(xiàn)這僅僅只是區(qū)別于s對(duì)象中的id對(duì)象的一個(gè)局部對(duì)象,等到構(gòu)造函數(shù)結(jié)束時(shí),該局部對(duì)象的局部生命期到期而不銷毀。10/1/202323

初始化表調(diào)用構(gòu)造函數(shù)如果一個(gè)類A的對(duì)象作為另一個(gè)類B的數(shù)據(jù)成員,則在類B的對(duì)象創(chuàng)建過程中,調(diào)用其構(gòu)造函數(shù)的過程中,數(shù)據(jù)成員(類A的對(duì)象)會(huì)自動(dòng)調(diào)用類A的構(gòu)造函數(shù)。如果類A的構(gòu)造函數(shù)為有參函數(shù)時(shí),則在程序中必須在類B的構(gòu)造函數(shù)的括號(hào)后面加一“:”和被調(diào)用的類A的構(gòu)造函數(shù),且調(diào)用類A的構(gòu)造函數(shù)時(shí)的實(shí)參值必須來自類B的形參表中的形參。這種方法稱為初始化表的方式調(diào)用構(gòu)造函數(shù)。這種在構(gòu)造函數(shù)的參數(shù)列表的右括號(hào)后面,花括號(hào)前面,用冒號(hào)引出構(gòu)造函數(shù)的調(diào)用表,可以省略類型名稱,但卻行創(chuàng)建對(duì)象之職。10/1/202324類X的構(gòu)造函數(shù)的定義格式應(yīng)為:

X::X(參數(shù)表0):成員1(參數(shù)表1),成員2(參數(shù)表

2),…,成員n(參數(shù)表n){

……}其中,參數(shù)表1提供初始化成員1所需的參數(shù),參數(shù)表2提供初始化成員2所需的參數(shù),依此類推。并且這幾個(gè)參數(shù)表的中的參數(shù)均來自參數(shù)表0,另外,初始化X的非對(duì)象成員所需的參數(shù),也由參數(shù)表0提供。在構(gòu)造新類的對(duì)象過程中,系統(tǒng)首先調(diào)用其子對(duì)象的構(gòu)造函數(shù),初始化子對(duì)象;然后才執(zhí)行類X自己的構(gòu)造函數(shù),初始化類中的非對(duì)象成員。對(duì)于同一類中的不同子對(duì)象,系統(tǒng)按照它們?cè)陬愔械恼f明順序調(diào)用相應(yīng)的構(gòu)造函數(shù)進(jìn)行初始化,而不是按照初始化表的順序。10/1/202325例:#include<iostream>using

namespacestd;//class

StudentID{intvalue;public:StudentID(int

id=0)//有參構(gòu)造函數(shù){value=id;cout

<<"Assigning

student

id

"

<<value

<<endl;}};//對(duì)剛才的例子進(jìn)行改進(jìn)10/1/202326class

Student{string

name;StudentID

id;public:Student(string

n="no

name",

int

ssID=0):id(ssID),name(n){cout<<"Constructing

student

"<<n<<"\n";}};//intmain(){Student

s("Randy",98);Student

t("Jenny");}//==========================10/1/2023274.構(gòu)造順序10/1/202328在程序中,各種作用域的對(duì)象很多,有些對(duì)象還包含在別的對(duì)象里面,有些對(duì)象早在main函數(shù)開始運(yùn)行之前就已經(jīng)建立了。創(chuàng)建對(duì)象的惟一途徑是調(diào)用構(gòu)造函數(shù)。構(gòu)造函數(shù)時(shí)一段程序,所以構(gòu)造對(duì)象的先后順序不同,直接影響程序執(zhí)行的先后順序,導(dǎo)致不同的運(yùn)行結(jié)果。C++給構(gòu)造對(duì)象的順序做了專門的規(guī)定。

局部對(duì)象局部和靜態(tài)對(duì)象是指塊作用域(局部作用域)和文件作用域的對(duì)象。它們的聲明順序與它們?cè)诔绦蛑谐霈F(xiàn)的順序是一致的。見課本307頁例9.8在C中,所有的局部變量(沒有對(duì)象)都是在函數(shù)開始執(zhí)行時(shí)統(tǒng)一創(chuàng)建的,創(chuàng)建的順序是根據(jù)變量在程序中按語句行出現(xiàn)的順序。而C++卻不同,它是根據(jù)運(yùn)行中定義對(duì)象的順序來決定對(duì)象創(chuàng)建的順序。而且,靜態(tài)對(duì)象只創(chuàng)建一次。10/1/202329

全局對(duì)象和全局變量一樣,所有全局對(duì)象在主函數(shù)啟動(dòng)之前,全部已近被構(gòu)造。因?yàn)闃?gòu)造過程是程序語句的執(zhí)行過程,所以,可以想象在程序啟動(dòng)之前,已經(jīng)有程序語句(構(gòu)造函數(shù))在那里被執(zhí)行過了。同一工程不同代碼文件全局對(duì)象的創(chuàng)建沒有明確順序規(guī)定.對(duì)策:不要讓不同文件的全局對(duì)象互為依賴.因?yàn)橐蕾嚲哂邢群笮?,而其全局?duì)象的創(chuàng)建不能保證該依賴性發(fā)揮作用.全局對(duì)象在main函數(shù)啟動(dòng)之前生成,而調(diào)試則在main函數(shù)啟動(dòng)之后.對(duì)策:調(diào)試時(shí),應(yīng)先將全局對(duì)象作為局部對(duì)象來運(yùn)行觀察.或者,在構(gòu)造函數(shù)中添加輸出語句來觀察運(yùn)行過程.10/1/202330

成員對(duì)象成員對(duì)象的構(gòu)造順序按類定義的出現(xiàn)順序classA{public:A(int

x){

cout<<"A:"<<x<<"->";

}};//classB{public:B(int

x){

cout<<"B:"<<x<<"->";

}};//class C按A、B的順序定義對(duì)象成員,其構(gòu)造函數(shù)又按b、a的順序進(jìn)行構(gòu)造。到底聽誰的,以定義順序說了算。classC{A

a;B

b;public:C(int

x,int

y):b(x),a(y){

cout<<"C\n";

}};//-----------------------------------intmain(){C

c(15,9);}1/0/=/1=/2=02=3========================31

構(gòu)造位置全局?jǐn)?shù)據(jù)區(qū):全局對(duì)象,靜態(tài)全局對(duì)象,靜態(tài)局部對(duì)象,常對(duì)象類的靜態(tài)數(shù)據(jù)成員也存放在該數(shù)據(jù)區(qū)。目的是為了讓對(duì)象的生命周期與運(yùn)行的程序等壽命。棧區(qū):局部對(duì)象在函數(shù)中定義好、局部對(duì)象,隨著被調(diào)用的返回而析構(gòu)(銷毀)。動(dòng)態(tài)存儲(chǔ)區(qū)(也稱堆區(qū)):用new申請(qǐng)的對(duì)象用delete銷毀。特殊地址空間除此之外,還可以指定特殊地址空間,存放對(duì)象10/1/202332回顧10/1/2023335.拷貝構(gòu)造函數(shù)10/1/202334對(duì)象本體與對(duì)象實(shí)體:對(duì)象本體也是對(duì)象主體,對(duì)象實(shí)體則還包括屬于對(duì)象的衍生物,如,某個(gè)人體是人類對(duì)象的主體,然而某人還擁有父母,房產(chǎn)等屬于某人的世系或資產(chǎn),描述人的屬性不僅僅只是人體數(shù)據(jù).從形式上看,對(duì)象除了包括數(shù)據(jù)成員,還包括指向數(shù)據(jù)的指針.對(duì)象本體與對(duì)象實(shí)體是不一致就是說有時(shí)我們會(huì)需要把a(bǔ)對(duì)象的屬性全部轉(zhuǎn)給b對(duì)象,對(duì)象本體與對(duì)象實(shí)體一致就是你要將a對(duì)象的屬性賦給a對(duì)象本身。對(duì)于一個(gè)簡單的變量的初始化方法是用一個(gè)常量或變量初始化另一個(gè)變量,例如:double

x=12.36;double

y=x;疑問:前面介紹了用構(gòu)造函數(shù)初始化對(duì)象,那么能不能像簡單變量的初始化一樣,直接用一個(gè)對(duì)象來初始化另一個(gè)對(duì)象呢?答案是肯定的。例:以定義的一個(gè)Point類為例,說明用一個(gè)對(duì)象來初始化另一個(gè)對(duì)象。Point

pt1(10,20);Point

pt2=pt1;那么,后一句也可寫成Point

pt2(pt1);它是用pt1初始化pt2,此時(shí),pt2各個(gè)成員的值與pt1各個(gè)成員的值相同,也就是說,pt1各個(gè)成員的值被復(fù)制到pt2相應(yīng)的成員當(dāng)中。在這個(gè)初始化過,實(shí)際上調(diào)用了一個(gè)拷貝構(gòu)造函數(shù)。1程0/1/當(dāng)202中335拷貝構(gòu)造函數(shù):拷貝構(gòu)造函數(shù)是C++中引入的一種新的構(gòu)造函數(shù)。定義一個(gè)拷貝構(gòu)造函數(shù)的方式是:類名(const

類名

&形式參數(shù)){

函數(shù)體}由此可看出拷貝構(gòu)造函數(shù)的特點(diǎn):拷貝構(gòu)造函數(shù)的名稱與類的名稱相同,且它只有一個(gè)參數(shù),該參數(shù)就是對(duì)該類對(duì)象的引用。拷貝構(gòu)造函數(shù)的功能是用于實(shí)現(xiàn)對(duì)象值的拷貝,通過將一個(gè)同類對(duì)象的值拷貝給一個(gè)新對(duì)象,來完成對(duì)新對(duì)象的初始化,即用一個(gè)對(duì)象去構(gòu)造另外一個(gè)對(duì)象。(3)每個(gè)類都有一個(gè)拷貝構(gòu)造函數(shù)10/1/202336以本類對(duì)象為常量引用參數(shù)的構(gòu)造函數(shù):class

Date{public:Date();Date(const

Date&

d);//

...};Date

x; //調(diào)用無參構(gòu)造函數(shù)

Date

y(x);//調(diào)用拷貝構(gòu)造函數(shù)10/1/202337例:默認(rèn)拷貝構(gòu)造函數(shù):若類中沒有定義拷貝構(gòu)造函數(shù),則系統(tǒng)會(huì)悄悄定義一個(gè)默認(rèn)空拷貝構(gòu)造函數(shù):Date(const

Date&d){}默認(rèn)拷貝構(gòu)造函數(shù)體一定是空的.空拷貝構(gòu)造函數(shù)負(fù)責(zé)將傳遞的對(duì)象到新創(chuàng)的對(duì)象做對(duì)象本體的位對(duì)位拷貝.(甚至連指針值都相等,即與參數(shù)對(duì)象擁有共同的資源)10/1/202338自定義拷貝構(gòu)造函數(shù):為了達(dá)到對(duì)象實(shí)體也就是對(duì)象整體復(fù)制目的,就需要另外定義一個(gè)拷貝構(gòu)造函數(shù),以覆蓋默認(rèn)的拷貝構(gòu)造函數(shù):見課本例315頁9.13自定義拷貝構(gòu)造名也是類名,它是構(gòu)造函數(shù)的重載,一旦自定義了拷貝構(gòu)造函數(shù),默認(rèn)的拷貝構(gòu)造函數(shù)就不再起作用了。在自定義拷貝構(gòu)造函數(shù)之前,我們進(jìn)行拷貝對(duì)象構(gòu)造時(shí),都是在用默認(rèn)的拷貝構(gòu)造函數(shù),因?yàn)槟菚r(shí)的對(duì)象本體與對(duì)象實(shí)體是一致的。所以,自定義拷貝構(gòu)造函數(shù)在對(duì)象本體與對(duì)象實(shí)體不一致時(shí),便是需要的,否則無此需要。10/1/202339自定義拷貝構(gòu)造函數(shù)體的工作不負(fù)責(zé)位對(duì)位對(duì)象復(fù)制,一般來說,它負(fù)責(zé)資源分配和由此而來的指針修改.

class

Person{char*

pName;public:Person(char*

pN="noName"){pName

=newchar[strlen(pN)+1];if(pName)

strcpy(pName,pN);}Person(const

Person&

s){pName

=newchar[strlen(s.pName)+1];if(pName)

strcpy(pName,

s.pName);}~Person(){delete[]

pName;}10/1/20}2;3406.析構(gòu)函數(shù)10/1/202341當(dāng)一個(gè)對(duì)象被定義時(shí),系統(tǒng)自動(dòng)調(diào)用構(gòu)造函數(shù)為該對(duì)象分配相應(yīng)的資源,當(dāng)對(duì)象使用完畢后,這些系統(tǒng)資源需要在對(duì)象消失前被釋放。人為的動(dòng)態(tài)內(nèi)存釋放工作由析構(gòu)函數(shù)來完成,析構(gòu)函數(shù)時(shí)一種特殊的成員函數(shù),它的意義是做關(guān)于對(duì)象失效之前瞬間的

善后工作。它的功能與構(gòu)造函數(shù)的工作正好相反,是用來釋放

一個(gè)對(duì)象。我們知道有內(nèi)存申請(qǐng),也就有內(nèi)存釋放。一般來說,需要定義構(gòu)造函數(shù)的類也需要定義析構(gòu)函數(shù),不需要構(gòu)造函數(shù)

的類,也無須定義析構(gòu)函數(shù)。所以析構(gòu)函數(shù)和構(gòu)造函數(shù)是成對(duì)

出現(xiàn)的。定義:10/1/202342析構(gòu)函數(shù)的定義方式為:~類名(){函數(shù)體}特點(diǎn):析構(gòu)函數(shù)名與構(gòu)造函數(shù)名相同,但它前面必須加一個(gè)“~”,用以與析構(gòu)函數(shù)相區(qū)別;在定義析構(gòu)函數(shù)時(shí),不能指定任何返回類型,也沒有參數(shù),而且不能重載。因此在一個(gè)類中只能有一個(gè)析構(gòu)函數(shù)。析構(gòu)函數(shù)可以被用戶調(diào)用,也可以被系統(tǒng)調(diào)用。在下面兩種情況下,析構(gòu)函數(shù)會(huì)被自動(dòng)調(diào)用a、如果一個(gè)對(duì)象被定義在一個(gè)函數(shù)體內(nèi),則當(dāng)這個(gè)函數(shù)結(jié)束時(shí),該對(duì)象的析構(gòu)函數(shù)被自動(dòng)調(diào)用。b、當(dāng)一個(gè)對(duì)象是使用new運(yùn)算符動(dòng)態(tài)創(chuàng)建時(shí)的,在使用delete運(yùn)算符自動(dòng)釋放時(shí),delete將會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)。每一個(gè)類若沒有顯示地定義為一個(gè)類定義析構(gòu)函數(shù),編譯系統(tǒng)會(huì)自動(dòng)地生成一個(gè)默認(rèn)的析構(gòu)函數(shù),默認(rèn)析構(gòu)函數(shù)時(shí)一個(gè)空函數(shù),實(shí)際上什么操作都不進(jìn)行。10/1/202343例:程序中三個(gè)類A、B、C分別有一個(gè)析構(gòu)函數(shù)。代碼如下:classA{public:A(){cout<<"A->";

}~A(){

cout<<"<-~A";

}};//-------------------------classB{public:B(){

cout<<"B->";

}~B(){

cout<<"<-~B";

}};//-------------------------classC{public:C(){

cout<<"C->";

}~C(){

cout<<"<-~C";

}};//-------------------------void

func(){cout<<"\nfunc:

";A

a;cout<<"ok->";static

B

b;C

c;}//----------------------------intmain(){cout<<"main:

";for(int

i=1;

i<=2;

++i){for(int

j=1;

j<=2;

++j)if(i==2)

C

c;

else

A

a;B

b;}func();func();}//=================10/1/202344注:(1)析構(gòu)函數(shù)總是出現(xiàn)在對(duì)象的生命期結(jié)束之時(shí)。靜態(tài)對(duì)象在程序運(yùn)行結(jié)束時(shí)析構(gòu)。對(duì)于一個(gè)簡單的類來說,大多可以直接使用系統(tǒng)提供的默認(rèn)析構(gòu)函數(shù)。但是,如果在類的對(duì)象中分配有動(dòng)態(tài)內(nèi)存(如:用new申請(qǐng)分配的內(nèi)容)時(shí),就必須為該類提供適當(dāng)?shù)奈鰳?gòu)函數(shù),完成清理工作。對(duì)象被析構(gòu)的順序與對(duì)象建立時(shí)的順序正好相反。對(duì)象析構(gòu)與構(gòu)造函數(shù)的關(guān)系是棧數(shù)據(jù)結(jié)構(gòu)中的入棧和出棧的關(guān)系,即最后構(gòu)造的對(duì)象先被析構(gòu)。棧底封閉指針10/1/2023457.

對(duì)象轉(zhuǎn)型與賦值

用于轉(zhuǎn)型的構(gòu)造函數(shù)5/8與5.0/8的結(jié)果是不同的,原因是C++執(zhí)行了兩種不同的操作。編譯器會(huì)將5.0/8中的整數(shù)8自動(dòng)轉(zhuǎn)換成double,匹配兩個(gè)

double數(shù)的除法操作。這是內(nèi)部數(shù)據(jù)類型所具有的轉(zhuǎn)換功能。但是,對(duì)于類類型,其自動(dòng)轉(zhuǎn)換的功能必須編程實(shí)現(xiàn)。那就是定義一個(gè)含有一個(gè)參數(shù)的構(gòu)造函數(shù)。例:class

Student{public:Student(const

string&n);};void

fn(Student&

s);intmain(){string

t=“jenny”;fn(t);//參數(shù)為string,卻能匹配Student類型1}0/1/202346剛才的例子也是在告知,如何將string對(duì)象轉(zhuǎn)換成一個(gè)Student對(duì)象。如果有重載函數(shù):void fn(string

&s){cout<<“ok\n”;}則main函數(shù)中的fn(t)函數(shù)調(diào)用將會(huì)馬上匹配。否則,匹配了void

fn(Student&

s)函數(shù)。從fn(Student&)和Student(conststring)可以推得fn(string)調(diào)用,這就是構(gòu)造函數(shù)用來從一種類型轉(zhuǎn)換成另一種類型的能力。對(duì)象轉(zhuǎn)型的規(guī)則:只會(huì)嘗試含有一個(gè)參數(shù)的構(gòu)造函數(shù)如果有二義性,則會(huì)放棄嘗試推導(dǎo)是一次性的,不允許多步推導(dǎo)10/1/202347

對(duì)象拷貝對(duì)象賦值即對(duì)象拷貝:兩個(gè)已經(jīng)存在的對(duì)象之間的復(fù)制Person

d(“Ranny”)Person

g;d=g; //對(duì)象賦值對(duì)象賦值便是使用類中的賦值操作符.如果類中沒有定義賦值操作符,則系統(tǒng)悄悄地定義一個(gè)默認(rèn)的賦值操作符:Person&

operator=(const

Person&

p){memcpy(*this,

*p,

sizeof(p));}10/1/202348當(dāng)對(duì)象本體與對(duì)象實(shí)體不同時(shí),則對(duì)象賦值操作符與拷貝構(gòu)造函數(shù)一樣

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論