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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

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

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

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

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

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

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

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

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

則編譯器報錯。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】使用指針操作數據#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、指針的用處實際編程時,很少直接定義指針變量指向某個變量,然后通過指針間接訪問該變量。指針的實際應用傳遞函數參數,實現對實參的間接修改。訪問類中成員數據和成員函數;管理堆中的數據(動態(tài)內存管理);【例7-3】用指針交換兩個整數“函數”章中有swap函數,不成功的交換原因:參數是變量的值=》單向的傳遞辦法:參數是變量的地址=》訪問的是同一內存空間-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;}使用指針訪問數組定義數組后,數組的所有元素在內存中連續(xù)存儲數組地址:數組中首個元素的地址。inta[]={2,3,6,1};int*pa=a;-13-aa[0]2320002004a[1]6120082012a[2]a[3]或pa=&a[0];指針變量pa指向數組a傳遞數組的本質上只是傳遞數組起始地址,在average

函數中,通過指針變量間接訪問數組元素。pa++;指針變量pa指向數組a+1-14-【例7-4】使用指針訪問數組#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);傳遞的是實參數組的起始地址

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

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

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

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

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

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

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

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

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

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

泄漏。-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,將釋放對應的空間,如果對該空間再次調用delete,將導致程序崩潰。int*pNumber=newint;deletepNumber;deletepNumber;//*pNumber;delete指針后,該指針將成為懸擺指針(或野指針、迷失

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

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

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

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

}intmain(){ fun();……}2000pa棧52000堆fun返回后,pa被釋放,5所占用的內存不可訪問!!Xdeletepa;-28-本章內容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內存分配)7.3創(chuàng)建和使用引用7.4數據成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構造函數中的深拷貝與淺拷貝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。可引用的目標可為內存中的任何數據對象建立引用,不能創(chuàng)建指向數據類型的引用。intsomeInt=5;int&rSomeInt=someInt;SimpleCatmyCat;;SimpleCat&rCatRef=myCat;int&ref1=int;SimpleCat&ref2=SimpleCat;-33-X2、空指針和空引用指針未初始化或被delete時,應將NULL賦值給它引用不能為空,定義引用時,不能將其初始化為0或NULL,也不能不指定引用對象。不能讓引用指向內存中不確定區(qū)域數據,否則會造成程序的運行異常。-34-3、引用傳遞函數參數函數的傳參方式按引用傳參形參是實參的引用通過引用傳參,允許在函數中修改實參對象,或者返回多個值按值傳參實參傳遞值,形參是變量,保存實參的值(副本)函數返回后形參被清除,對形參的修改不會影響實參;函數最多只能返回一個值。按址傳遞實參傳遞地址,形參是指針變量,保存實參的地址通過形參的值找到實參的地址,再讀取地址內的值(*)修改*形參的值,就是修改形參的值-35--36-【例7-8】交換2個整數(引用)voidswap(int&rx,int&ry){ inttemp;

temp=rx; rx=ry; ry=temp; std::cout<<rx <<“,“<<ry<<std::endl;}rx和ry是x和y的引用,調用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語句,函數只能返回1個值指針或引用在調用之前定義好保存多個結果的對象將對象用指針或引用方式傳入函數在函數內部修改對象的值,則計算結果保存到引用目標中常規(guī)的返回值常用于報告處理錯誤。-37--38-【例7-9】求一個整數的平方和立方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記錄計算結果是否越界

如返回true表示計算成功,

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

到引用的變量。-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-本章內容安排7.1創(chuàng)建和使用指針變量7.2棧和堆(new與delete動態(tài)內存分配)7.3創(chuàng)建和使用引用7.4數據成員中的指針與引用7.5堆中創(chuàng)建、訪問與刪除對象7.6復制構造函數中的深拷貝與淺拷貝7.7指針和引用的陷阱-41-1、指針數據成員類中可能會包含指針數據成員,每個指針指向堆中的對象。通常在構造函數(或其它成員函數)中分配內存,在析構函數中釋放內存。含有指針數據成員的類,都要編寫析構函數釋放內存,編譯器提供的缺省析構函數不會釋放內存,將造成內存泄漏。-42-【例7-10】含有指針數據成員的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;}; 為含有指針成員的類編寫構造與析構函數。-43-Rectangle::Rectangle(){ itsLength=newint(2); itsWidth=newint(5);}Rectangle::~Rectangle(){ deleteitsLength; deleteitsWidth;}voidRectangle::output(){ std::cout<<getLength()<<","<<getWidth()<<"\n";}在構造函數中分配內存,在析構函數中釋放內存。在堆中分配內存時,通過()可以指定初始值,將itsAge所

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

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

數據,初始化為2int*p=newint[10],分配10

個數據,不初始化?!纠?-10】含有指針數據成員的Rectangle類-44-2、this指針每個成員函數都有一個隱含的參數,this指針,是指向其函數被調用的對象。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、常對象與指向常對象的指針類的常成員函數中不能修改對象的數據成員,否則編譯器會報錯。定義常對象后,通過對象只能調用其常成員函數。定義指向常對象的指針后,通過該指針也只能調用常成員函數。-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;};通過初始化列表對數據成員進行初始化const修飾指針三種形式intnumber=5;constint*pOne

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

的值;但可以指向別的整數。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位于*號左側,表示指向內容為常量(內容受保護)

若const位于*號右側,表示指針本身為常量(指針受保護)-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、引用提高效率對象值傳遞的問題將對象作為函數參數按值傳遞時,會創(chuàng)建該對象的備份;同樣函數返回對象時,也會創(chuàng)建對象的備份,存在效率和性能上的問題。對于大型對象,創(chuàng)建備份的代價非常高,增加了內存消耗,同時降低運行速度每次創(chuàng)建備份時,都會調用構造函數(復制構造函數),函數返回時要銷毀臨時對象,調用其析構函數。-53-【例7-13-1】對象的值作為函數的參數【例7-13-2】對象的指針作為函數的參數【例7-13-3】對象的引用作為函數的參數-54-【例7-13-1】對象的值作為函數的參數RectangleFunctionOne(Rectangler){ returnr;}intmain(){ RectanglemyRectangle;

FunctionOne(myRectangle); return0;}調用函數時創(chuàng)建theCat,調用復制構造函數復制myCat

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

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

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

引起對象的復制構造以及返回后的析構函數調用。函數返回臨時指針變量,保存的是theCat存儲的地址

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

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

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

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

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

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

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

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

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

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

deletespeed;speed=NULL;}構造函數中分配內存,析構函數中釋

放內存。默認復制構造函數中,不會分配內存

只是執(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設置新速度,也可以直接修改數據*speed+=1,但通過調用setSpeed可以隱藏實現細節(jié)。更進一步:setSpeed(getSpeed()+1);不用關心speed

到底是如何存儲等實現細節(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;}復制構造后,新創(chuàng)建的dallas

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

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

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

溫馨提示

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

評論

0/150

提交評論