7指針與引用第章_第1頁
7指針與引用第章_第2頁
7指針與引用第章_第3頁
7指針與引用第章_第4頁
7指針與引用第章_第5頁
已閱讀5頁,還剩76頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第7章指針與引用-2-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構(gòu)造函數(shù)中的深拷貝與淺拷貝7.7指針和引用的陷阱-3-1、地址的概念地址:內(nèi)存單元的編號就是該單元的地址,它表明了內(nèi)存單元在內(nèi)存中的相對位置變量保存在內(nèi)存中,不同類型變量占用內(nèi)存單元的數(shù)量不同變量的地址:變量占用的首個內(nèi)存單元的地址2000…02…2002inta;如,變量a占用的是內(nèi)存的2000~2003四個單元,變量a的地址為2000。源代碼中寫a=5;我們可以理解為將5賦值給變量a;而計算機在執(zhí)行程序時,只是將5送入2000~2003四個內(nèi)存單元中-4-【例7_1】查看變量的地址#include<iostream>intmain(){

shortsVar=5; longlVar=65535; floatfVar=3.14f;

std::cout<<"Short:\t"<<sVar<<"\tAdd:\t"<<&sVar<<"\n"; std::cout<<"Long:\t"<<lVar<<"\tAddr:\t"<<&lVar<<"\n"; std::cout<<"Float:\t"<<fVar<<"\tAddr:\t"<<&fVar<<"\n“; return0;}取變量地址運算符:&sVar。\t為轉(zhuǎn)義字符,輸出一個制表符。\\用于輸出\,\"輸出雙引號,\’輸出

單引號每個變量都有確定的地址編譯器確定應分配內(nèi)存

的數(shù)量,及對應的地址程序員不用關(guān)心地址的細節(jié),

只需知道如何訪問變量即可-5-2、定義指針變量C++中可以定義特殊的變量(指針變量),用于保存普通變量的地址int*pAge=NULL;定義變量時,變量名pAge前面的*,表示pAge是一個變量,

用來存儲一個整型變量的地址,

編譯器會為指針變量分配內(nèi)存單元。指針變量的類型:可保存其地址的變量數(shù)據(jù)類型。NULL為預定義常量,表示空指針,NULL通常等價于0。良好編程習慣:定義指針變量時應對其執(zhí)行初始化,未初

始化的指針稱為野指針,非常危險。為指針變量賦值通過&、=運算符,可以將某個變量的地址保存到指針變量中,稱指針變量指向某個變量。inthowOld=50;int*pAge;pAge=&howOld;int*pAge2=&howOld;pAge=howOld;double*p=&howOld;-6-指針變量中存儲的地址值實際上是一個整數(shù)值,但不能將

整數(shù)值直接賦值給指針變量。賦值時,取地址的變量類型必須與指針變量類型一致。否

則編譯器報錯。X-7-指針變量

inta=5;

int*pa;pa=&a;指針變量pa指向變量a3、間接運算符*對指針變量執(zhí)行間接運算*,又稱為解除引用,將獲得指針所指向地址處的值。unsignedshorthowOld=50;unsignedshortyourAge;yourAge=howOld;unsignedshorthowOld=50;unsignedshort*pAge=&howOld;unsignedshortyourAge;yourAge=*pAge;-8--9-【例7-2】使用指針操作數(shù)據(jù)#include<iostream>intmain(){

intmyAge; int*pAge=&myAge; myAge=5; std::cout<<"MyAge:\t"<<myAge<<"\n"; std::cout<<"*pAge:\t"<<*pAge<<"\n";

*pAge=7; std::cout<<"MyAge:\t"<<myAge<<"\n"; std::cout<<"*pAge:\t"<<*pAge<<"\n"; return0;}注意*的不同用處定義指針變量inta=50;int*pAge;pAge=&a;int*p=&a;定義指針變量后,指針變量前的*表示解除引用,表示“存儲在……處的值”*pAge=50;//將50保存到pAge所指處*(&a)a*可作為乘法運算符*pAge=yourAge*2;-10--11-4、指針的用處實際編程時,很少直接定義指針變量指向某個變量,然后通過指針間接訪問該變量。指針的實際應用傳遞函數(shù)參數(shù),實現(xiàn)對實參的間接修改。訪問類中成員數(shù)據(jù)和成員函數(shù);管理堆中的數(shù)據(jù)(動態(tài)內(nèi)存管理);【例7-3】用指針交換兩個整數(shù)“函數(shù)”章中有swap函數(shù),不成功的交換原因:參數(shù)是變量的值=》單向的傳遞辦法:參數(shù)是變量的地址=》訪問的是同一內(nèi)存空間-12-voidswap(int*x,int*y){

inttemp;temp=*x; *x=*y; *y=temp; std::cout<<*x<<","<<*y<<std::endl;}#include<iostream>voidswap(int*a,int*b);intmain(){ inta=3,b=2; swap(&a,&b); std::cout<<a<<","<<b<<std::endl; return0;}使用指針訪問數(shù)組定義數(shù)組后,數(shù)組的所有元素在內(nèi)存中連續(xù)存儲數(shù)組地址:數(shù)組中首個元素的地址。inta[]={2,3,6,1};int*pa=a;-13-aa[0]2320002004a[1]6120082012a[2]a[3]或pa=&a[0];指針變量pa指向數(shù)組a傳遞數(shù)組的本質(zhì)上只是傳遞數(shù)組起始地址,在average

函數(shù)中,通過指針變量間接訪問數(shù)組元素。pa++;指針變量pa指向數(shù)組a+1-14-【例7-4】使用指針訪問數(shù)組#include<iostream>doubleaverage(intarray[],intsize);constintN=10;intmain(){ inta[N]; int*p=a;//或者p=&a[0]; for(intk=0;k<N;k++)

*(p+k)=k; doubleave; ave=average(a,N); std::cout<<"average="<<ave<<"\n"; return0;}或者p[k]=k;或者(int*array,intsize);或者(int*,int);傳遞的是實參數(shù)組的起始地址

-15-【例7-4】數(shù)組作為函數(shù)參數(shù)intaverage(intarray[],intsize){ intsum=0;

for(inti=0;i<size;++i) { sum+=array[i]; } returnsum/size;}數(shù)組本身并不包含數(shù)據(jù)元素個數(shù)的信息,傳遞數(shù)組或指針

時,往往傳遞輔助參數(shù)表示元素個數(shù)。本質(zhì)上是:int*array傳遞的是實參數(shù)組的起始地址

或者sum+=*(array+i); int*p;

for(p=array;p<array+size;p++) { sum+=*p; }-16-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構(gòu)造函數(shù)中的深拷貝與淺拷貝7.7指針和引用的陷阱-17-1、程序的內(nèi)存區(qū)域每個程序運行時,會創(chuàng)建5個內(nèi)存區(qū)域全局名稱空間:全局變量棧:局部變量和函數(shù)形參堆:自由存儲區(qū)寄存器:用于內(nèi)部管理,CPU內(nèi)部的臨時數(shù)據(jù)、指令緩存,狀態(tài)管理代碼空間:保存程序指令-18-棧機制棧用于保存函數(shù)中定義的局部變量和函數(shù)形參。調(diào)用函數(shù)時,系統(tǒng)在棧中創(chuàng)建所有局部變量及形參,函數(shù)返回后,系統(tǒng)將清除棧中對應的數(shù)據(jù)。棧中的數(shù)據(jù)往往都有變量與其對應,通過變量名訪問。棧中數(shù)據(jù)的創(chuàng)建和清除由系統(tǒng)自動完成。局部變量隨著函數(shù)的返回被丟棄,無法再訪問。全局變量存在于整個程序的運行期間,整個程序中都能

訪問,但全局變量容易出錯、難以理解與維護,避免使用。-19-堆機制堆是預留給程序員的大塊內(nèi)存,程序員可以從堆中請求內(nèi)存空間,使用完成后釋放內(nèi)存空間。請求的內(nèi)存空間通過指針標識,通過指針間接訪問,堆中的內(nèi)存空間沒有變量與其對應;函數(shù)返回后系統(tǒng)會自動清理棧,而不會清理堆,堆空間在顯示釋放前,一直可以訪問;堆中請求的空間由程序員負責釋放,不再需要的信息保留在堆中稱為內(nèi)存泄漏。-20-2、動態(tài)請求堆空間使用new運算符,可以從堆中分配內(nèi)存。情況一:分配單個數(shù)據(jù)int*pPointer;pPointer=newint;*pPointer=75;從堆中分配可存儲1個int數(shù)據(jù)的空間。堆中分配的內(nèi)存,沒有對應的變量,只能通過指針間接訪問從堆中分配內(nèi)存可能會失敗,使用指針前一定要判斷是否

分配成功。老式編譯器失敗后返回NULL指針,新的編譯器

會拋出異常(后面討論)。-21-動態(tài)請求堆空間情況二:分配多個數(shù)據(jù)int*pPointer;pPointer=newint[10];*pPointer=75;*(pPointer+1)=85;分配堆空間時,可以指定分配數(shù)據(jù)的數(shù)量,從而請求可保存

多個數(shù)據(jù)的存儲空間。*pPointer訪問所指向的第一個數(shù)據(jù),*(pPointer+n)訪問之

后的第n個數(shù)據(jù),注意不能超過所分配的內(nèi)存界限。-22-3、釋放堆空間使用delete運算符,可以釋放請求的堆空間使用完堆內(nèi)存區(qū)域后,必須調(diào)用delete釋放相應空間,將內(nèi)存歸還給堆,避免內(nèi)存泄漏。情況一:釋放單個數(shù)據(jù)int*pData=newint;deletepData;//將請求的空間歸還給堆情況二:釋放多個數(shù)據(jù)空間int*pData=newint[10];delete[]pData;//將請求的空間歸還給堆動態(tài)請求的多個數(shù)據(jù),如果只使用delete釋放,將造成內(nèi)存

泄漏。-23-【例7-5】new和delete示例#include<iostream>intmain(){ int*pHeap=newint;

if(pHeap==NULL) { std::cout<<"Error!NomemoryforpHeap!\n"; return1; }

*pHeap=7; std::cout<<"*pHeap:"<<*pHeap<<"\n";

deletepHeap; return0;}-24-4、懸擺指針問題堆中動態(tài)請求的存儲空間,對指針執(zhí)行1次delete,將釋放對應的空間,如果對該空間再次調(diào)用delete,將導致程序崩潰。int*pNumber=newint;deletepNumber;deletepNumber;//*pNumber;delete指針后,該指針將成為懸擺指針(或野指針、迷失

指針),解析或再次delete該指針,會導致程序崩潰。釋放指針所指向堆內(nèi)存后,應將指針賦值為NULL或指向重新分配的內(nèi)存空間。deletepNumber;pNumber=NULL;良好編程習慣:對指針執(zhí)行運算前,判斷該指針是否為NULL-25-delete的本質(zhì)voidfun(){ int*pa=newint(5); *pa=5; ……

deletepa; cout<<pa<<endl;}2000pa棧52000堆Xdelete只是釋放pa所指向的堆空間,對指針pa本身沒有任何

影響。此時pa仍然指向原先的內(nèi)存位置,變成了野指針。pa是位于棧中的局部變量,fun返回后pa由系統(tǒng)自動銷毀。5、避免內(nèi)存泄漏典型情況一:沒有釋放所指內(nèi)存之前將指針指向新分配的內(nèi)存int*pNumber=newint;*pNumber=75;pNumber=newint;*pNumber=85;-26-pNumber指向新分配的存儲空間后,原先分配的內(nèi)容為75的

內(nèi)存無法訪問,也無法再釋放!deletepNumber;-27-避免內(nèi)存泄漏典型情況二:在函數(shù)內(nèi)分配的內(nèi)存空間,函數(shù)返回之前沒有釋放voidfun(){ int*pa=newint; *pa=5;

}intmain(){ fun();……}2000pa棧52000堆fun返回后,pa被釋放,5所占用的內(nèi)存不可訪問!!Xdeletepa;-28-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構(gòu)造函數(shù)中的深拷貝與淺拷貝7.7指針和引用的陷阱1、創(chuàng)建引用創(chuàng)建引用時,必須同時指定被引用的對象,引用一旦建立后,不能再引用其它對象。intsomeInt=5;int&rSomeInt=someInt;-29-rSomeInt是一個int引用,被初始化指向someInt。將來對rSomeInt的操作都等價于對someInt的操作。-30-【例7-6】引用的示例#include<iostream>intmain(){ intintOne;

int&rSomeRef=intOne;

intOne=5; std::cout<<"intOne:"<<intOne<<"\n"; std::cout<<"rSomeRef:"<<rSomeRef<<"\n";

rSomeRef=7; std::cout<<"intOne:"<<intOne<<"\n"; std::cout<<"rSomeRef:"<<rSomeRef<<"\n"; return0;}【例7-7】獲取引用的地址通過&運算符取引用的地址時,實際上取得的是被引用對象的地址,它們是同一個東西。#include<iostream>intmain(){ intintOne;

int&rSomeRef=intOne; intOne=5; std::cout<<"intOne:"<<intOne<<"\n"; std::cout<<"rSomeRef:"<<rSomeRef<<"\n";

std::cout<<"&intOne:"<<&intOne<<"\n"; std::cout<<"&rSomeRef:"<<&rSomeRef<<"\n"; return0;}-31-不能改變引用的目標不能試圖通過賦值運算符改變引用的對象。intsomeInt=5;int&rSomeInt=someInt;intanotherInt=10;rSomeInt=anotherInt;-32-rSomeInt仍然引用的是someInt,通過賦值運算符,只是

將anotherInt的值賦給rSomeInt,也就是someInt。可引用的目標可為內(nèi)存中的任何數(shù)據(jù)對象建立引用,不能創(chuàng)建指向數(shù)據(jù)類型的引用。intsomeInt=5;int&rSomeInt=someInt;SimpleCatmyCat;;SimpleCat&rCatRef=myCat;int&ref1=int;SimpleCat&ref2=SimpleCat;-33-X2、空指針和空引用指針未初始化或被delete時,應將NULL賦值給它引用不能為空,定義引用時,不能將其初始化為0或NULL,也不能不指定引用對象。不能讓引用指向內(nèi)存中不確定區(qū)域數(shù)據(jù),否則會造成程序的運行異常。-34-3、引用傳遞函數(shù)參數(shù)函數(shù)的傳參方式按引用傳參形參是實參的引用通過引用傳參,允許在函數(shù)中修改實參對象,或者返回多個值按值傳參實參傳遞值,形參是變量,保存實參的值(副本)函數(shù)返回后形參被清除,對形參的修改不會影響實參;函數(shù)最多只能返回一個值。按址傳遞實參傳遞地址,形參是指針變量,保存實參的地址通過形參的值找到實參的地址,再讀取地址內(nèi)的值(*)修改*形參的值,就是修改形參的值-35--36-【例7-8】交換2個整數(shù)(引用)voidswap(int&rx,int&ry){ inttemp;

temp=rx; rx=ry; ry=temp; std::cout<<rx <<“,“<<ry<<std::endl;}rx和ry是x和y的引用,調(diào)用swap時沒有創(chuàng)建新的局部變

量,對rx和ry的操作就是對x和y的操作。#include<iostream>voidswap(int&rx,int&ry);intmain(){ intx=5,y=10;

swap(x,y);

std::cout<<x<<“,"<<y<<std::endl; return0;}4、通過引用返回多個值返回多個值的途徑通過return語句,函數(shù)只能返回1個值指針或引用在調(diào)用之前定義好保存多個結(jié)果的對象將對象用指針或引用方式傳入函數(shù)在函數(shù)內(nèi)部修改對象的值,則計算結(jié)果保存到引用目標中常規(guī)的返回值常用于報告處理錯誤。-37--38-【例7-9】求一個整數(shù)的平方和立方boolfactor(intn,int&pSquared,int&pCubed){

boolflag=false;

pSquared=n*n; pCubed=n*n*n; if(pSquared<0||n*pCubed<0) flag=false; else flag=true; returnflag;}返回多個值(引用)flag記錄計算結(jié)果是否越界

如返回true表示計算成功,

返回false表示計算失敗。通過傳入的引用將計算結(jié)果保存

到引用的變量。-39-【例7-9】返回多個值(引用)#include<iostream>boolfactor(intn,int&pSquared,int&pCubed);intmain(){ intnumber,squared,scubed; boolflag; std::cout<<"Enteranumber:"; std::cin>>number;

flag=factor(number,squared,scubed);

if(flag) { std::cout<<"number:“<<number<<"\n" <<"squared:“<<squared<<"\n" <<"scubed:“<<scubed<<"\n"; } else std::cout<<"Errorencountered!\n"; return0;}-40-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構(gòu)造函數(shù)中的深拷貝與淺拷貝7.7指針和引用的陷阱-41-1、指針數(shù)據(jù)成員類中可能會包含指針數(shù)據(jù)成員,每個指針指向堆中的對象。通常在構(gòu)造函數(shù)(或其它成員函數(shù))中分配內(nèi)存,在析構(gòu)函數(shù)中釋放內(nèi)存。含有指針數(shù)據(jù)成員的類,都要編寫析構(gòu)函數(shù)釋放內(nèi)存,編譯器提供的缺省析構(gòu)函數(shù)不會釋放內(nèi)存,將造成內(nèi)存泄漏。-42-【例7-10】含有指針數(shù)據(jù)成員的Rectangle類classRectangle{public: Rectangle(); ~Rectangle(); intgetLength(){return*itsLength;} intgetWidth(){return*itsWidth;} voidsetLength(intlength){*itsLength=length;} voidsetWidth(intwidth){*itsWidth=width;} voidoutput();private: int*itsLength; int*itsWidth;}; 為含有指針成員的類編寫構(gòu)造與析構(gòu)函數(shù)。-43-Rectangle::Rectangle(){ itsLength=newint(2); itsWidth=newint(5);}Rectangle::~Rectangle(){ deleteitsLength; deleteitsWidth;}voidRectangle::output(){ std::cout<<getLength()<<","<<getWidth()<<"\n";}在構(gòu)造函數(shù)中分配內(nèi)存,在析構(gòu)函數(shù)中釋放內(nèi)存。在堆中分配內(nèi)存時,通過()可以指定初始值,將itsAge所

指單元初始化為2,將itsWeight所指單元初始化為5。int*p=newint,分配1個數(shù)據(jù)

不初始化int*p=newint(2),分配1個

數(shù)據(jù),初始化為2int*p=newint[10],分配10

個數(shù)據(jù),不初始化。【例7-10】含有指針數(shù)據(jù)成員的Rectangle類-44-2、this指針每個成員函數(shù)都有一個隱含的參數(shù),this指針,是指向其函數(shù)被調(diào)用的對象。this指針由編譯器隱含插入,通常情況下不需要訪問this指針,也可以顯示使用。主要用途:在特殊情況下可以獲得對象自身的地址。setAge(intage);setAge(SimpleCat*constthis,intage);程序員無需維護this指針的創(chuàng)建和銷毀,由編譯器完成。-45-【例7-11】使用this的Rectangle類classRectangle{public: Rectangle(); ~Rectangle(); intgetLength(){returnlength;} intgetWidth(){returnwidth;} voidsetLength(intlength){this->length=length;} voidsetWidth(intwidth){this->width=width;} voidoutput();private: intlength; intwidth;};3、常對象與指向常對象的指針類的常成員函數(shù)中不能修改對象的數(shù)據(jù)成員,否則編譯器會報錯。定義常對象后,通過對象只能調(diào)用其常成員函數(shù)。定義指向常對象的指針后,通過該指針也只能調(diào)用常成員函數(shù)。-46--47-【例7-12】使用const的Rectangle類#include<iostream>classRectangle{public: Rectangle():length(5),width(10){} ~Rectangle(){} intgetLength()const{returnlength;} intgetWidth()const{returnwidth;} voidsetLength(intlength){this->length=length;} voidsetWidth(intwidth){this->width=width;} voidoutput();private: intlength; intwidth;};通過初始化列表對數(shù)據(jù)成員進行初始化const修飾指針三種形式intnumber=5;constint*pOne

=&number;int*constpTwo=&number;constint*constpThree=&number;-48-pOne:指向整型常量的指針,通過pOne不能修改所指向變量

的值;但可以指向別的整數(shù)。pOne=&anotherNumber;√*pOne=10;Xconst修飾指針三種形式intnumber=5;constint*pOne

=&number;int*constpTwo=&number;constint*constpThree=&number;-49-pTwo:指向整型的常量指針,pTwo不能再指向其它變量,但可以通過指針修改所指向變量的值。pTwo=&anotherNumber;×*pTwo=10;√const修飾指針三種形式intnumber=5;constint*pOne

=&number;int*constpTwo=&number;constint*constpThree=&number;-50-pThree:指向整型常量的常量指針,pThree不能再指向其它

變量,通過指針也不能修改所指向變量的值。pThree=&anotherNumber;×*pThree=10;×const修飾指針三種形式intnumber=5;constint*pOne

=&number;int*constpTwo=&number;constint*constpThree=&number;-51-若const位于*號左側(cè),表示指向內(nèi)容為常量(內(nèi)容受保護)

若const位于*號右側(cè),表示指針本身為常量(指針受保護)-52-const練習???#include<iostream>intmain(){

Rectangle*pRect=newRectangle;

constRectangle*pConstRect=newRectangle; Rectangle*constpConstPtr=newRectangle;

pRect->setWidth(20); //pConstRect->setWidth(20); pConstPtr->setWidth(30);

std::cout<<“Width:“<<pRect->getWidth()<<“\n”; std::cout<<“Width:”<<pConstRect->getWidth()<<“\n”; std::cout<<“Width:”<<pConstPtr->getWidth()<<“\n”; return0;}

4、引用提高效率對象值傳遞的問題將對象作為函數(shù)參數(shù)按值傳遞時,會創(chuàng)建該對象的備份;同樣函數(shù)返回對象時,也會創(chuàng)建對象的備份,存在效率和性能上的問題。對于大型對象,創(chuàng)建備份的代價非常高,增加了內(nèi)存消耗,同時降低運行速度每次創(chuàng)建備份時,都會調(diào)用構(gòu)造函數(shù)(復制構(gòu)造函數(shù)),函數(shù)返回時要銷毀臨時對象,調(diào)用其析構(gòu)函數(shù)。-53-【例7-13-1】對象的值作為函數(shù)的參數(shù)【例7-13-2】對象的指針作為函數(shù)的參數(shù)【例7-13-3】對象的引用作為函數(shù)的參數(shù)-54-【例7-13-1】對象的值作為函數(shù)的參數(shù)RectangleFunctionOne(Rectangler){ returnr;}intmain(){ RectanglemyRectangle;

FunctionOne(myRectangle); return0;}調(diào)用函數(shù)時創(chuàng)建theCat,調(diào)用復制構(gòu)造函數(shù)復制myCat

內(nèi)容;函數(shù)返回后調(diào)用析構(gòu)函數(shù),并銷毀theCat。函數(shù)返回時創(chuàng)建臨時對象,調(diào)用復制構(gòu)造函數(shù)復制theCat的內(nèi)容;最后要析構(gòu)并銷毀臨時對象。-55-【例7-13-2】指針提高效率Rectangle*

FunctionOne(Rectangle*r){ returnr;}intmain(){ RectanglemyRectangle;

FunctionOne(&myRectangle); return0;}theCat只是局部指針變量,接收myCat的地址,不會

引起對象的復制構(gòu)造以及返回后的析構(gòu)函數(shù)調(diào)用。函數(shù)返回臨時指針變量,保存的是theCat存儲的地址

值,不會引起對象的復制構(gòu)造以及析構(gòu)。指針變量占用的存儲空間較少,可以忽略。-56-【例7-13-3】引用提高效率Rectangle&

FunctionOne(Rectangle&r){ returnr;}intmain(){ RectanglemyRectangle;

FunctionOne(myRectangle); return0;}theCat是myCat的引用,不會引起構(gòu)造及析構(gòu)。返回的臨時引用是theCat的引用,也就是對myCat的

引用,不會引起構(gòu)造與析構(gòu)。傳遞引用不會創(chuàng)建新的對象,引用只是別名。引用和指針的負作用傳遞引用或地址,可以提高效率,避免構(gòu)造與析構(gòu)函數(shù)的調(diào)用開銷,但也會產(chǎn)生副作用。在函數(shù)內(nèi)部,通過引用或地址,可以間接修改原始數(shù)據(jù),從而造成意外的修改或破壞。為了保護實參不被意外修改,通常使用const限定形參,以實現(xiàn)保護的目的doublefunc(constRectangle&r){ returnr.getWidth()*r.getLength();}-57--58-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6深拷貝與淺拷貝7.7指針和引用的陷阱堆中創(chuàng)建對象類似在堆中創(chuàng)建1個普通類型數(shù)據(jù)空間,也可以在堆中創(chuàng)建1個類的對象。Rectangle*pCat=newRectangle;-59-創(chuàng)建對象時會調(diào)用類的構(gòu)造函數(shù),此處調(diào)用缺省構(gòu)造函數(shù)每當在棧中或堆中創(chuàng)建對象時,都將調(diào)用構(gòu)造函數(shù)。-60-內(nèi)存結(jié)構(gòu)2000myRectangle棧Rectangle*myRectangle=newRectangle;….//使用myRectangledeletemyRectangle;堆300430002000lengthwidth523000Xnew構(gòu)造函數(shù)delete引起析構(gòu)函數(shù)X執(zhí)行delete操作后,將調(diào)用對象的析構(gòu)函數(shù),然后釋放堆

中的內(nèi)存(對象本身)。堆中釋放對象訪問對象方法訪問堆中創(chuàng)建對象的方法,只能通過指針間接訪問,有兩種訪問方式指針解除引用后,通過.運算符訪問

(*pRectangle).getWidth();通過指向運算符->直接訪問

pRectangle->getWidth();-61--62-【例7-14】堆中使用對象#include<iostream>intmain(){

Rectangle*myRectangle=newRectangle; std::cout<<"myRectangleis“<<myRectangle->getLength() <<"length.\n";

myRectangle->setWidth(4); std::cout<<"myRectangleis“<<(*myRectangle).getWidth() <<"Width.\n";

deletemyRectangle; return0;}-63-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構(gòu)造函數(shù)中的深拷貝與淺拷貝7.7指針和引用的陷阱-64-復制構(gòu)造函數(shù)創(chuàng)建現(xiàn)有對象的備份時,將調(diào)用復制構(gòu)造函數(shù)。如果類中沒有寫復制構(gòu)造函數(shù),編譯器提供默認的復制構(gòu)造函數(shù),實現(xiàn)對象間數(shù)據(jù)成員逐一復制(淺復制)。復制構(gòu)造函數(shù)調(diào)用時機用現(xiàn)有對象初始化并創(chuàng)建新對象;按值將對象傳入函數(shù)函數(shù)按值返回對象-65-復制構(gòu)造函數(shù)的形式復制構(gòu)造函數(shù)符合構(gòu)造函數(shù)的形式接收1個參數(shù):同類對象的引用,為了防止對同類對象的修改,常聲明為const引用Tricycle(constTricycle&trike);通過傳入的trike對象,創(chuàng)建和trike“相同”的新對象。-66-淺復制的問題如果類中只包含簡單數(shù)據(jù)成員,沒有指向堆的指針,使用編譯器提供的默認復制構(gòu)造函數(shù),程序能夠良好運行。如果類中包含指向堆中數(shù)據(jù)的指針,淺復制將出現(xiàn)嚴重問題淺復制直接復制兩個對象間的指針成員,導致兩個指針指向堆中同一塊內(nèi)存區(qū)域一個對象的修改將導致另一個對象的修改一個對象超出作用域,將導致內(nèi)存釋放,使得另一個對象的指針無效,對其訪問將導致程序異常。-67-淺復制的問題-68-編寫自己的復制構(gòu)造函數(shù)含有指針成員的類,通常需要編寫復制構(gòu)造函數(shù)。實現(xiàn)“深復制”,創(chuàng)建對象備份時,為新對象在堆中分配自己的內(nèi)存,并將現(xiàn)有值復制到新內(nèi)存中。如果一個類需要在構(gòu)造函數(shù)中分配內(nèi)存,需要編寫配套

的析構(gòu)函數(shù)以釋放內(nèi)存,同時需要實現(xiàn)相應的復制構(gòu)造函數(shù)以及復制運算符函數(shù)(下一章)。-69-Tricycle類classTricycle{public:

Tricycle();Tricycle(constTricycle&rhs);~Tricycle();intgetSpeed()const{return*speed;}voidsetSpeed(intnewSpeed){*speed=newSpeed;}voidpedal();voidbrake();private:

int*speed;};speed所指內(nèi)存在堆中分配-70-Tricycle類Tricycle::Tricycle(){

speed=newint;*speed=5;}Tricycle::Tricycle(constTricycle&rhs){

speed=newint;*speed=rhs.getSpeed();}Tricycle::~Tricycle(){

deletespeed;speed=NULL;}構(gòu)造函數(shù)中分配內(nèi)存,析構(gòu)函數(shù)中釋

放內(nèi)存。默認復制構(gòu)造函數(shù)中,不會分配內(nèi)存

只是執(zhí)行speed=rhs.speed。-71-Tricycle類voidTricycle::pedal(){setSpeed(*speed+1);std::cout<<“Pedaling"<<getSpeed()<<“\n";}voidTricycle::brake(){setSpeed(*speed-1);std::cout<<“Pedaling"<<getSpeed()<<“\n";}pedal中通過setSpeed設(shè)置新速度,也可以直接修改數(shù)據(jù)*speed+=1,但通過調(diào)用setSpeed可以隱藏實現(xiàn)細節(jié)。更進一步:setSpeed(getSpeed()+1);不用關(guān)心speed

到底是如何存儲等實現(xiàn)細節(jié)。-72-測試Tricycle類#include<iostream>intmain(){Tricyclewichita;

Tricycledallas(wichita);

wichita.setSpeed(10);std::cout<<"Wichita";

wichita.pedal();std::cout<<"Dallas";dallas.pedal();std::cout<<"Wichita";

wichita.brake();std::cout<<"Dallas";

dallas.brake();return0;}復制構(gòu)造后,新創(chuàng)建的dallas

和wichita的狀態(tài)相同。復制構(gòu)造后,兩個對象是獨立

的對象,可獨立設(shè)置修改狀態(tài),

與引用關(guān)系不同。-73-深復制的內(nèi)存狀態(tài)-74-本章內(nèi)容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內(nèi)存分配)7.3創(chuàng)建和使用引用7.4數(shù)據(jù)成員中的指針與引用7.5堆中創(chuàng)建、訪

溫馨提示

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

評論

0/150

提交評論