C++面向?qū)ο蟪绦蛟O(shè)計(第4版)-課件 CH2_第1頁
C++面向?qū)ο蟪绦蛟O(shè)計(第4版)-課件 CH2_第2頁
C++面向?qū)ο蟪绦蛟O(shè)計(第4版)-課件 CH2_第3頁
C++面向?qū)ο蟪绦蛟O(shè)計(第4版)-課件 CH2_第4頁
C++面向?qū)ο蟪绦蛟O(shè)計(第4版)-課件 CH2_第5頁
已閱讀5頁,還剩182頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第2章C++基礎(chǔ)

教學(xué)目標(biāo):掌握C++語言中的基本概念和非面向?qū)ο蟮恼Z言機制,了解C++新語言標(biāo)準(zhǔn)與新語言特點,具備應(yīng)用C++新語言特性編寫C++程序的基本能力。教學(xué)重點:C++的數(shù)據(jù)類型、類型推斷、類型轉(zhuǎn)換、常量、引用、指針、函數(shù)原型、默認參數(shù)、函數(shù)重載、內(nèi)聯(lián)函數(shù)、Lamada、范圍for、名字空間及其應(yīng)用、變量、文件。教學(xué)難點:

常量與指針、引用結(jié)合應(yīng)用,智能指針、Lamada函數(shù)、文件、類型轉(zhuǎn)換、函數(shù)參數(shù)、移動函數(shù)、靜態(tài)變量的作用域與生存期。2.1C++語言對C語言的數(shù)據(jù)類型擴展和類型定義1、C數(shù)據(jù)類型在C++中繼續(xù)可用2、C++對C的struct、enum、union進行了擴展C:結(jié)構(gòu)名、枚舉、聯(lián)合不是類型structsome_struct{……};structsome_structstruct_var;typedefstructsome_structstruct_type;C++:結(jié)構(gòu)名、聯(lián)合名為類型structsome_struct{……};some_struct

struct_var;C++允許在struct、union內(nèi)部設(shè)置函數(shù)

下面程序.c錯誤,.cpp無錯誤#include<stdio.h>#include<stdlib.h>struct

A{ intx; voidsetX(inta){x=a;}};intmain(){ Aa[10]; for(inti=0;i<10;i++) { a[i].setX(i); } for(inti=0;i<10;i++) { printf("a[%d]=%d\t",i,a[i]); }}2.1C++語言對C語言的數(shù)據(jù)類型擴展和類型定義3、enum和enumclassenumcolor{black,white,red,blue,yellow}; //C,C++98/03enumclasscolor1{black1,white1,red1,blue1,yellow1}; //C++11boolblack=false; //L1,錯誤,不能通過編譯boolblack1=false; //L2,正確enum是C語言中不限作用域的枚舉,稱為枚舉(enumeration)enumclass是C++11標(biāo)準(zhǔn)enum的補充,稱為枚舉器(enumerator)區(qū)別:enum的作用域不受定義它的“{}”限制,在上一級作用域內(nèi)仍然有效。因此,color定義的black標(biāo)識在語句l1處仍然有效,再定義black就屬于重定義錯誤了。enumclass的作用域局限在定義它的“{}”中。因此,語句l2定義black1時并不會與color1中的枚舉常量black1發(fā)生沖突,因為black1的作用域被限定在定義它的“{}”中,不會延伸到語句l2處2.2C++程序變量設(shè)計的基本思想1.面向過程與面向?qū)ο蟪绦蜃兞吭O(shè)計思想的主要區(qū)別“程序=數(shù)據(jù)結(jié)構(gòu)+算法”程序設(shè)計基本方法:①定義程序要用到的數(shù)據(jù)結(jié)構(gòu)和全局變量;②定義操作數(shù)據(jù)和全局變量的若干函數(shù),定義函數(shù)時,也是先定義好要使用的所有局部變量才開始編寫函數(shù)執(zhí)行代碼;③在主程序(主函數(shù))中組織執(zhí)行流程,按次序調(diào)用各函數(shù),進行全局變量的運算和修改,實現(xiàn)程序功能。面向過程程序設(shè)計的基本思想structA{…

};intx,y,z;

intf1(…){

inti,j,k;

for(i=0;i<n;i++){x+=10;

……}}intf1(…){…}voidmain(){

inta,b,c;structAs;f1(a,b,c);

……f2(s);}1.先定義數(shù)據(jù)結(jié)構(gòu)和全部變量2.再定義函數(shù),函數(shù)也是先定義變量,再寫操行語句主要問題:1.全局變量生存期長,耗占內(nèi)存時間長2.全局變量可能與局部變量沖突3.在編寫大程序后部分代碼量,查找最前面的全局變量定義較難。2.2C++程序變量設(shè)計的基本思想1.面向過程與面向?qū)ο蟪绦蜃兞吭O(shè)計思想的主要區(qū)別“盡量減小變量的作用域范圍,少用(甚至不用)全局變量,變量應(yīng)就近定義,就近使用”。面向?qū)ο蟪绦蛟O(shè)計語言允許在任何語句位置定義變量。包括for、while、do-while循環(huán)語句內(nèi)部以及switch和if等復(fù)合句中都可以定義變量。面向?qū)ο蟪绦蜃兞康幕舅枷搿纠?-2】在C++中,在for循環(huán)內(nèi)部定義局部變量。//Eg2-2.cpp#include<iostream>usingnamespacestd;voidmain(){intn=1;for(inti=1;i<=10;i++){intk;n=n*i;}//i、k作用域結(jié)束

inti=0;}//n作用域結(jié)束1.變量就近定義,就近使用2.隨用隨定義優(yōu)點:1.對象通常較大(數(shù)據(jù)成員多),減少全局變量可減少其對內(nèi)存的長期耗占2.減少了與局部變量的沖突3.變量隨用隨定義,寫大程序時不須找最前面的全局。1.左值和右值

intx,y;

定義了變量的左、右兩個值左值代表變量名對應(yīng)的內(nèi)存區(qū)域,是“能夠放在賦值語句左邊的值”變量:x(指x對應(yīng)的內(nèi)存區(qū)域)右值指變量對應(yīng)內(nèi)存區(qū)域中的值,是“放在賦值語句右邊的值”常量:2,-3,表達式:7+34.7變量:x(指在x對應(yīng)內(nèi)存區(qū)域中存放的值)有變量的表達式:x+7+y2.3左值、右值和斷言89內(nèi)存區(qū)域xyx=x+1“=”左邊的x是其左值,即x對應(yīng)的內(nèi)存單元,右邊的x指其右值82.3左值、右值和斷言2.斷言assert是一種檢測錯誤的宏,可以用來對表達式的結(jié)果進行判斷,如果為假,就會退出程序。在軟件開發(fā)階段運用斷言進行測試非常有效,能夠快速找到錯誤并進行修改【例2-3】在C++中,用斷言檢查平方根函數(shù)的參數(shù)必須大于0。//Eg2-3.cpp#include<iostream>#include<cassert>#include<cmath>usingnamespacestd;doublesqrtd(doublex){assert(x>=0.0);returnsqrt(x);}intmain(){cout<<sqrtd(-6.0)<<endl;return0;}編譯并運行程序,將產(chǎn)生下面的輸出Assertionfailed:x>=0.0,fileF:\cprogram\ui\abc.cpp,line8abnormalprogramtermination2.4指針本節(jié)要掌握的內(nèi)容C++的指針new、delete指針與常量之間的關(guān)系0指針、void指針、智能指針智能指針2.4.1指針概述1、C++內(nèi)存分配方式靜態(tài)分配(靜態(tài)變量)編譯器在處理源代碼時為變量分配內(nèi)存,其效率較高,但缺少靈活性(要求程序執(zhí)行之前就知道變量所需的內(nèi)存類型和數(shù)量)動態(tài)分配(動態(tài)變量)程序執(zhí)行時調(diào)用運行時刻庫函數(shù)來分配變量的內(nèi)存。兩者的區(qū)別靜態(tài)變量是有名字的變量,可以通過名字對它所代表的內(nèi)存進行操作;動態(tài)變量是沒有名字的內(nèi)存變量,只能通過指針進行操作。靜態(tài)變量的分配和釋放由編譯器自動處理,動態(tài)變量的分配與釋放必須由程序員控制。2.4.1指針概念的回顧2、動態(tài)內(nèi)存分配---指針對類型T,T*是“到T的指針”,即一個類型為T*的變量,能存一個類型T的對象的地址charc;……c=‘a(chǎn)’;charp*p=&c;pc?????‘a(chǎn)’?&c*P內(nèi)存??局部變量與指針在堆棧中的分配#include<iostream>usingnamespacestd;voidmain(intargc,char*argv[]){ doubled,*pd;//L1 intn=0,*p;//L2 d=3.2;//L3 p=&n;//L4 pd=&d;//L5 *p=10;//L6 cout<<"&d:"<<&d<<"\td:"<<d<<endl; cout<<"&pd:"<<&pd<<"\tpd:"<<pd<<endl; cout<<"&n:"<<&n<<"\tn:"<<n<<endl; cout<<"&p:"<<&p<<"\tp:"<<p<<endl; p=newint(8);//動態(tài)內(nèi)存配 cout<<"*p:"<<&*p<<endl;}圖2-1VC6.0中建立的堆棧#include<iostream>usingnamespacestd;voidmain(intargc,char*argv[]){ doublef1=1,f2=2; inta=5,b=6; double*pf=&f1; int*pi=&a; cout<<"add:f1"<<&f1<<"\t"<<f1<<endl; cout<<"add:f2"<<&f2<<"\t"<<f2<<endl; cout<<"add:a"<<&a<<"\t"<<a<<endl; cout<<"add:b"<<&b<<"\t"<<b<<endl; cout<<"add:pf"<<&pf<<endl; cout<<"add:pi"<<&pi<<endl; cout<<"pfadd:\t"<<pf<<"\t*pf:"<<*pf<<endl; --pf; cout<<"--pfadd:\t"<<pf<<"\t*pf:"<<*pf<<endl; cout<<"piadd:\t"<<pi<<"\t*pi:"<<*pi<<endl; --pi; cout<<"--piadd:\t"<<pi<<"\t*pi:"<<*pi<<endl; printf("HelloWorld!\n");}在VS2015下指針與內(nèi)存單元的對應(yīng)關(guān)系如下頁所示!指針與內(nèi)存關(guān)系案例0041FD280041FD180041FD0C0041FD00地址指針變量Pf-1pfpiPi-1內(nèi)存指針與內(nèi)存變量關(guān)系

doublef1=1,f2=2;inta=5,b=6;double*pf=&f1;int*pi=&a;--pf;--pi;

0f1f2abpf0041FCE4pi……..2.4.1指針概念的回顧0041FCE8從f1和f2的地址可以看出VS2105在兩雙精度之間有預(yù)留空間2.4.1指針概述指針是一個復(fù)雜的概念,它能夠指向(保存)不同類型變量的內(nèi)存地址。例如:int*pi; //pi是指向int的指針int**pc;//pc是指向int指針的指針int*pA[10];//pA是指向int的指針數(shù)組int(*f)(int,char);//f是指向具有兩個參數(shù)的函數(shù)的指針int*f(int)//f是一個函數(shù),返回一個指向int的指針2.4.2空指針,void*,獲取數(shù)組首、尾元素位置的指針空指針空指針是沒有指向任何內(nèi)存單元的指針。C++11中NULL,0,nullptr意義等價,用于將指針設(shè)置為空指針:T*ptr=0;*ptr=NULL;*ptr=nullptr;C++11新定義T是指任意數(shù)據(jù)類型2.4.2空指針,void*,獲取數(shù)組首、尾元素位置的指針2.void空指針(1)指針與地址的關(guān)系每個指針都是一個內(nèi)存地址,但都有一個相關(guān)的類型指示編譯器怎樣解釋指針?biāo)付▋?nèi)存區(qū)域的內(nèi)容,以及該內(nèi)存區(qū)域應(yīng)該跨越多少個內(nèi)存單元。相同類型的指針進行比較或相互賦值才有意義。(2)void*指針void*指針只表示與它相關(guān)的值是個內(nèi)存地址,但該內(nèi)存的數(shù)據(jù)類型是未知的。void*是能夠接受任何數(shù)據(jù)類型的特殊指針。void*最重要的用途是作為函數(shù)的參數(shù),向函數(shù)傳遞一個類型可變的對象。另一種用途就是從函數(shù)返回一個無類型的對象。在使用void*指針之前,必須顯式地將它轉(zhuǎn)換成某種數(shù)據(jù)類型的指針后使用,其他操作都不允許。【例2-4】void*指針的應(yīng)用。

#include<iostream>usingnamespacestd;voidmain(){ inti=4,*pi=&i;

void*pv; doubled=9,*pd=&d;

pv=&i; //L1:正確

pv=pi; //L2:正確// cout<<*pv<<endl; //L3:錯誤

pv=pd; //L4:正確

cout<<*(double*)pv; //L5:正確,輸出9}2.4.2空指針,void*,獲取數(shù)組首、尾元素位置的指針void*pv分別指向了int、double類型的數(shù)據(jù),但使用前必須進行類型轉(zhuǎn)換!2c4282c2491c181cipipvdpd3.begin()和end()C++11<iterator>頭文件的兩個函數(shù),用于確定指向數(shù)組首元素和尾元素后一位置的指針,方便遍歷數(shù)組。inta[]={1,2,3,4,5,6,7,8,9,10};for(int*p=begin(a);p!=end(a);p++) cout<<*p<<",";cout<<endl;for循環(huán)依次輸出數(shù)據(jù)組a的元素值!2.4.2空指針,void*,獲取數(shù)組首、尾元素位置的指針2.4.3內(nèi)存的分配

和釋放1、動態(tài)存儲管理的概念

系統(tǒng)為每個程序提供了一個可在程序執(zhí)行時期間申請使用的內(nèi)存空間,這個內(nèi)存空間被稱為空閑存儲區(qū)或堆(heap),運行時刻的內(nèi)存分配就稱為動態(tài)內(nèi)存分配。2、C用mallc和free進行動態(tài)內(nèi)存分配,操作麻煩#include<stdlib.h>//malloc和free定義于此頭文件中voidmain(){ int*p; //從堆中分配1個int對象需要的內(nèi)存并將轉(zhuǎn)換為int類型 p=(int*)malloc(sizeof(int)); *p=23;

free(p); //釋放堆內(nèi)存}2.4.3內(nèi)存的分配

和釋放3.C++動態(tài)內(nèi)存分可由new,delete運算符完成New用于從內(nèi)存中分配指定大小的內(nèi)存用法1:p=newtype;用法2:p=newtype(x);//分配并設(shè)初值x用法3:p=newtype[n];

//數(shù)組delete用于釋放new分配的堆內(nèi)存用法1:deletep;用法2:delete[]p;//回收數(shù)組4、【例2-5】用new和delete分配與釋放堆內(nèi)存。#include<iostream>usingnamespacestd;voidmain(){ int*p1,*p2,*p3;

p1=newint; //分配一個能夠存放int類型數(shù)據(jù)的內(nèi)存區(qū)域

p2=newint(10); //分配一個int類型大小的內(nèi)存區(qū)域,并將10存入其中

p3=newint[10]; //分配能夠存放10個整數(shù)的數(shù)組區(qū)域

if(!p3)//程序中常會見到這樣的判定 cout<<"allocationfailure"<<endl; //分配不成功顯示錯誤信息 *p1=5; *p3=1; p3[1]=2;p3[2]=3; //訪問指向數(shù)組的數(shù)組元素 cout<<"p1address:"<<&p1<<"value:"<<p1<<endl; cout<<"p2address:"<<&p2<<"value:"<<p2<<endl; cout<<"p3[0]address:"<<&p3<<"value:"<<p3<<endl; cout<<"p3[1]address:"<<&p3[1]<<"value:"<<p3[1]<<endl;

deletep1;deletep2; //釋放指向的內(nèi)存 //deletep3; //錯誤,只釋放了p3指向數(shù)組的第1個元素

delete[]p3; //釋放p3指向的數(shù)組}2.4.3內(nèi)存的分配

和釋放5、new、delete和malloc、free的區(qū)別

new能夠自動計算要分配的內(nèi)存類型的大小,不必用sizeof計算所要分配的內(nèi)存字節(jié)數(shù)new不需要進行類型轉(zhuǎn)換,它能夠自動返回正確的指針類型。new可以對分配的內(nèi)存進行初始化。new和delete可以被重載,程序員可以借此擴展new和delete的功能,建立自定義的存儲分配系統(tǒng)。

sizeof()被改為sizeof2.4.4智能指針

11C++智能指針的提出動態(tài)內(nèi)存分配是C++程序最容易出錯的地方,有時會忘記使用delete或free釋放為指針分配的動態(tài)內(nèi)存,造成內(nèi)存泄漏。為了更安全地管理動態(tài)內(nèi)存,C++提供了智能指針,用它們進行動態(tài)內(nèi)存分配和使用方的法同普通指針差不多,主要區(qū)別是智能指針會負責(zé)自動釋放所指向的對象,無須調(diào)用delete\free進行回收。智能指針的類型(定義于memory頭文件中)auto_ptrshared_ptrunique_ptrintmy_free(intflag1,char*buf){

if(flag1<1)

free(buf);

return0;}voidf(intflag){

char*buf=malloc(100);

//引起內(nèi)存漏

bugif(flag>1){my_free(flag,buf);If(flag>10)buf=malloc(100);

//mem-leakbug}voidmain(){f(1);f(10);}2.4.4智能指針

11C++3.智能指針定義x_ptr<type>p; //L1x_ptr<type>p2(p);//L2,適用于auto_ptr,share_ptrx_ptr<type>p3(newtype(x)) //L3其中,x_ptr代表auto_ptr、shared_ptr或unique_ptr,type則可以是任何數(shù)據(jù)類型。例如auto_ptr<int>p;auto_ptr<int>p2(p);auto_ptr<int>p3(newint(9));2.4.4智能指針

11C++3.智能指針之間賦值在定義時就為它分配動態(tài)內(nèi)存單元,不允許先定義智能指針,然后再為它分配動態(tài)存儲空間。x_ptr<type>p1,p2(newtype);//正確p1=newtype; //錯誤p1=p2;//錯誤同類型的auto_ptr、shared_ptr之間可以相互賦值,而unique_ptr指針之間不能相互賦值。unique_ptr<int>p4(newint(8));unique_ptr<int>p5=p4;//錯誤2.4.4智能指針

11C++3.智能指針與普通指針賦值智能指針和普通指針(“裸指針”)之間不能夠隨意賦值,即不能把智能指針指向普通內(nèi)存變量,或者把非智能指針賦值給智能指針??梢酝ㄟ^智能指針的get成員函數(shù)獲取智能指針中的指針后,再賦值給普通指針。intx=9;int*ip=newint(1);;//裸指針shared_ptr<int>sp(newint(8));//sp=&x; //錯誤//sp=ip; //錯誤//ip=sp; //錯誤ip=sp.get(); //正確2.4.4智能指針

11C++4.unique_ptr

c++11規(guī)范【例2-6】用unique_ptr指針返回輸入函數(shù)InputStudent(

)創(chuàng)建的學(xué)生對象。#include<iostream>usingnamespacestd;structStudent{stringname;intage;};

unique_ptr<Student>InputStudent(){unique_ptr<Student>stu(newStudent);cout<<"inputname,age"<<endl;cin>>stu->name;cin>>stu->age;returnstu;}

intmain(){unique_ptr<Student>ptr_s; //L1ptr_s=move(InputStudent()); //L2,可不寫movecout<<"name:"<<ptr_s->name<<"\nAge:"<<ptr_s->age<<endl;unique_ptr<int[]>pi{newint[10]}; //L3,分配一組堆對象for(inti=0;i<10;i++) //L4pi[i]=i*10;for(inti=0;i<10;i++) //L5cout<<pi[i]<<"\t";cout<<endl;}獨占指針獨占它所分配到的內(nèi)存空間使用權(quán),指針之間不允許相互賦值,也不允許用一個獨占指針初始化另一個獨占指針,否則在編譯時會發(fā)生錯誤。stu,pi都分配了動態(tài)內(nèi)存,但未用delete回收,它們會被自動回收!2.4.4智能指針

11C++5.unique_ptr

c++11規(guī)范【例2-6】用unique_ptr指針返回輸入函數(shù)InputStudent(

)創(chuàng)建的學(xué)生對象。#include<iostream>usingnamespacestd;structStudent{stringname;intage;};

unique_ptr<Student>InputStudent(){unique_ptr<Student>stu(newStudent);cout<<"inputname,age"<<endl;cin>>stu->name;cin>>stu->age;returnstu;}

intmain(){unique_ptr<Student>ptr_s; //L1ptr_s=move(InputStudent()); //L2,可不寫movecout<<"name:"<<ptr_s->name<<"\nAge:"<<ptr_s->age<<endl;unique_ptr<int[]>pi{newint[10]}; //L3,分配一組堆對象for(inti=0;i<10;i++) //L4pi[i]=i*10;for(inti=0;i<10;i++) //L5cout<<pi[i]<<"\t";cout<<endl;}獨占指針獨占它所分配到的內(nèi)存空間使用權(quán),指針之間不允許相互賦值,也不允許用一個獨占指針初始化另一個獨占指針,否則在編譯時會發(fā)生錯誤。stu,pi都分配了動態(tài)內(nèi)存,但未用delete回收,它們會被自動回收!2.3.4智能指針

11C++6.weak_ptr

//Eg2-8.cpp#include<iostream>#include<memory>usingnamespacestd;voidswap(shared_ptr<int>a,shared_ptr<int>b){intt=*a;*a=*b;*b=t;}

intmain(){shared_ptr<int>sp1(newint(9)),sp2(newint(7)),sp3(sp1);cout<<"1:sp1.count="<<sp1.use_count()<<endl;//L1weak_ptr<int>w1(sp1),w2(sp2); //定義方法cout<<"2:w1.count="<<w1.use_count()<<"\tsp1.count="<<sp1.use_count()<<endl; //L2cout<<"sp1="<<*sp1<<endl;//cout<<"w1="<<*w1<<endl;L3,錯誤,weak_ptr沒有解引用//swap(w1,w2);//L4,錯誤用法swap(w1.lock(),w2.lock());//L5,正確用法cout<<"*sp1="<<*sp1<<"\t*sp2="<<*sp2<<endl;//L6return0;}弱指針:主要用于協(xié)助共享指針工作。弱指針不占有內(nèi)存,沒有指針的解引用操作,但是能夠提供對一個或多個共享指針擁有的對象的訪問,且不參與引用計數(shù),可以用來解決兩個共享指針相互引用產(chǎn)生的死鎖問題。下面關(guān)于指針的說法錯誤的是()所有指針都是長度相同的內(nèi)存地址delete和free的功能都是釋放動態(tài)分配的內(nèi)存空間為share_ptr指針分配的空間需要用delete回收auto_ptr和unique_ptr指針采用自動回收內(nèi)存機制ABCD提交單選題1分2.5引用(Reference)1.概念“引用”即“別名”,即是某對象的另一個名字,引用的主要用途是為了描述函數(shù)的參數(shù)和返回值。特別是用于運算符的重載。2.類型左值引用右值引用3.定義類型

&左值引用名=變量名;類型

&&右值引用名=表達式;8x左值引用:為變量對應(yīng)的內(nèi)存區(qū)域定義的別名,代表內(nèi)存區(qū)域本身右值引用:為變量對應(yīng)內(nèi)存區(qū)域中的值定義的別名,代表內(nèi)存區(qū)域內(nèi)的數(shù)據(jù)(8)本身2.5.1左值引用1.概念“左值引用”即“變量的別名”,代表變量對應(yīng)的內(nèi)存區(qū)域,與原變量系同一內(nèi)存區(qū)域,具有完全相同的操作方法。由于歷史原因,也稱之為引用.2.定義類型&引用名=變量名;例如:inti=9; //L1int&ir=i; //L2ir與i是同一實體的不同名稱3.與指針區(qū)別

int*ip=&i;int&ir=i;2.5.1左值引用【例2-9】引用的簡單例子。//Eg2.9.cpp#include<iostream.h>voidmain(){ inti=9; int&ir=i; cout<<"i="<<i<<""<<"ir="<<ir<<endl; ir=20; cout<<"i="<<i<<""<<"ir="<<ir<<endl; i=12; cout<<"i="<<i<<""<<"ir="<<ir<<endl; cout<<"i的地址是:"<<&i<<endl; cout<<"ir的地址是:"<<&ir<<endl;}2.5.1左值引用3、使用引用應(yīng)該注意的事情引用不是值,不占用存儲空間引用在聲明時必須初始化,否則會產(chǎn)生編譯錯誤引用的初始值可以是一個變量或另一個引用引用可以視為“隱式指針”,但不分配存儲空間引用由類型標(biāo)準(zhǔn)符和一個取地址操作符來定義,必須被初始化,且不可重新賦值inti,k;int&r=i;int&m=r;//③r=&k //errorr=k; //ok

引用的地址就是其所引用的變量的地址intnum=50;int&rnum=num;int*p=#//p是指向num的指針,非引用;int*rp=rnum;//err,當(dāng)為int*rp=&rnum;2.5.1左值引用若一個變量聲明為T&,必須用一個T類型的變量或?qū)ο螅蚰軌蜣D(zhuǎn)換為T類型的對象進行初始化double&rr=1;可以有指針變量的引用,不能有指向引用的指針int*p;int*&rp=p; //okrp是一個引用,它引用的是指針int&*ra=a; //error,ra是一指針,指向一個引用。變量名只能是左值引用,不能作右值引用inta=1;int&&ra=a; //error2.5.1左值引用引用與數(shù)組可以建立數(shù)組或數(shù)組元素的引用,但不能建立引用數(shù)組原因:引用不分配內(nèi)存,一次只能為一個已有變量定義一個別名,而數(shù)組一次需要定義多個元素,所以不能定義引用數(shù)組inti=0,a[10]={1,2,3,4,5,6,7,8,9,10},*b[10];int(&ra)[10]=a;//L1:正確,ra是具有10元素的整型數(shù)組的引用int&aa=a[0];//L2:正確,數(shù)組元素的引用int*(&rpa)[10]=b;//L3:正確,rpa是具有10個整型指針的數(shù)組的引用int&ia[10]=a;//L4:錯誤,ia是引用數(shù)組,每個數(shù)組元素都是引用ra[3]=0;//L5:正確,數(shù)組引用的用法rpa[3]=&i;//L6:正確練習(xí):指出下列中的錯誤

intival=1.01; int&rval1=1.01; int&rval2=ival; int&rval3=&ival; int*pi=&ival; int&rval4=pi; int&rval5=*pi; int&*prval1=pi;constint&ival2=1; constint&*prval2=&ival;投屏:錯誤的有?2.5.1左值引用2.5.2右值引用、移動及其語義1.概念右值引用就是綁定到右值上的引用。右值引用是C++11為了支持移動操作而引入的新型引用類型,其重要特點就是只能綁定到即將銷毀的臨時對象上,比如常量或表達式。通過右值引用可以方便地將它引用的資源“移動”到另一個對象上。2.定義類型&&引用名=表達式;doubler=10;double&lr1=r;//正確,變量名代表左值double&lr2=r+10;//錯誤,引用只能是變量double&&rr=r;//錯誤,變量名代表左值,而&&需要右值double&&rr=r+10;//正確,rr是保存“r+10”計算結(jié)果20的臨時內(nèi)存單元的別名2.5.2右值引用、移動及其語義【例2-11】右值引用的定義和使用。#include<iostream>usingnamespacestd;voidmain(){ intx=10; int&r=x; //int&&ar=x;//L1:錯誤,變量名只能綁定到左值 int&&rx=x+10*3;//L2:正確,rx為右值引用,保存表達式值 cout<<"x="<<x<<"\trx="<<rx<<endl;//L3 x=20;//x變化不影響rx, cout<<"x="<<x<<"\trx="<<rx<<endl;//L4rx=40 inty=rx;//L5y=40 cout<<"y="<<y<<endl;//L6}2.5.2右值引用、移動及其語義左值引用&右值引用的區(qū)別關(guān)鍵理解:只要是引用(無論左引用還是右引用),都是只能是某內(nèi)存單元的別名,都對應(yīng)的是某內(nèi)存變量的地址。左值只能夠綁定到變量名(對應(yīng)變量的內(nèi)存區(qū)域),而且具有持久性(引用與其對就變量的作用域和生存期內(nèi)相同);右值只能綁定到常量,或者表達式求值過程中創(chuàng)建的臨時對象上,本來該臨時對象是短暫的,用完就會被銷毀,而右值引用“接管”了該臨時對象,使它可再次被使用(引用的作用域和生存期長于它所對應(yīng)的臨時變量)。左值持久,右值臨時Intx=9;Intf(){……returny;}Int&lr=x;Int&&rr1=x;//errInt&&rr1=move(x);Int&&rr2=f();Int&&rr3=x+9;x=f();VSx=rr2;2.6const和constexpr常量2.6.1、常量的定義C#define常量名稱常量

C++const類型常量名=常量表達式;//執(zhí)行期

constexpr類型

常量名=常量表達式;//編譯期

常量在定義時就必須初始化2.6.1、常量的定義1、常量注意事項①常量一經(jīng)定義就不能修改constinti=5; //定義常量Iconstexprintk=9;//定義常量ki=5; //錯誤,修改常量k++; //錯誤,修改常量②常量必須在定義時初始化constintn; //錯誤,常量n未被初始化constexprintk;//錯誤,常量n未被初始化③表達式可以出現(xiàn)在常量定義語句中,const中可以有變量名,但constexpr的表達式中不能有變量intj,k=9; //L1constinti1=10+k+6; //正確constexprinti1=10+k+6; //錯誤,k是變量2.6const和constexpr常量2.const和constexpr的區(qū)別constexpr

在編譯時進行初始化,const

在運行時初始化。constexpr常量的初始化表達式中的每部分值都是程序運之前就可以確定的字面值常量。const常量初始化表達式中可以有變量,其初始值可以在程序運行期取得。但一經(jīng)取得,就不可再被修改。constintn=size(); //L1:正確,但n值的取得是在執(zhí)行函數(shù)時。constexprintm=size();//L2:錯誤,程序編譯時不知道size()的值constinti=10;intj=21;constinti1=i+10; //L3:正確constintj1=j+10; //L4:正確constexprinti2=i+10; //L5:正確,編譯時可確定i值為10constexprintj2=j+10; //L6:錯誤,j是變量。2.6.2const、constexpr與指針1、const、constexpr與指針的限定關(guān)系指針與const的限定關(guān)系指針與constexpr的限定關(guān)系constexpr限定指針時,它只限制指針變量本身是常量,與它所指的變量沒有關(guān)系。個constexpr指針的初始值必須是nullptr、0,或存儲某個固定地址的對象。2.6.2const、constexpr與指針2、const限制變量訪問,避免非本意的數(shù)據(jù)修改舉例#include<iostream>usingnamespacestd;main(){inti;constintic=100;constint*ip=⁣ip=&i;//ok*ip=0//errint*consticp=&i;//icp=&j;//err*icp=200; cout<<"i="<<i<<endl;cout<<"*ip="<<*ip<<endl;cout<<"*icp="<<*icp<<endl;}icp是一個常量地址,此處企圖修改它ic100constip&ic100iicp&icconst2.6.2const、constexpr與指針3、指向常量的指針在指針定義前加const,表示指向的對象是常量。constinta=78;constintb=28;intc=18;constint*pi=&a;//定義指向常量的指針*pi=58; //error,不能修改指針指向的常量pi=&b; //ok,指針值可以修改*pi=68; //errorpi=&c; //ok*pi=88; //errorC=98; //ok*p是常量,但通過修改C的值而使*p發(fā)生了變化,這種用法就有問題了,2.6.2const、constexpr與指針例題:限制函數(shù)修改參數(shù)//eg.cpp#include<iostream.h>voidmystrcpy(char*Dest,constchar*Src){ while(*Dest++=*Src++);}voidmain(){ chara[20]="Howareyou!"; charb[20]; mystrcpy(b,a); cout<<b<<endl;}2.6.2const、constexpr與指針4、指針常量在指針定義語句的指針名前加const,表示指針本身是常量。char*constpc="aaaa"; //定義指針常量,在定義時必須初始化pc="bbbb"; //error,指針常量不能改變其指針值*pc="a"; //err,所指的內(nèi)容可改*pc='a'; //ok,在VC環(huán)境下產(chǎn)生運行錯誤,*(pc+1)='b'; //ok,在VC環(huán)境下產(chǎn)生運行錯誤pc++='y'; //errorconstintb=28;int*constpi=&b ;//error,pi不能變,但它所指的內(nèi)存單卻可以改//變,此處卻將它指向了一個不可變的內(nèi)存單元//,即://不能將constin*轉(zhuǎn)換成int*2.6.2const、constexpr與指針5、指向常量的常指針可以定義一個指向常量的常指針變量,它必須在定義時進行初始化。例如:constintci=7;intai=8;constint*constcpc=&ci; //指向常量的指針常量constint*constcpi=&ai; //okcpi=&ai; //error,*cpi=39; //error,ai=39; //ok,2.6.2const、constexpr與指針6、const、指針與變量賦值const對象的地址只能賦值給指向const對象的指針但是,指向const對象的指針可以指向常量對象,也可以指向非常量對象。

constdoubleminWage=9.60;//只能由指向常量的指針指向constdouble*ptr=&minWage;//ptr既可以指向常量,也可以指向非常量doubledval=3.14;ptr=&dval;*ptr=23;dval=23;double*p=&minWage;//是對?是錯?2.6.2const、constexpr與指針【例2-12】const與指針的關(guān)系。#include<iostream>usingnamespacestd;intmain(){char*constp0; //L1錯誤,p0是常量,必須初始化char*constp1="dukang"; //L2錯誤charconst*p2; //L3正確constchar*p3="dukang";

//L4正確constchar*constp4="dukang";

//L5正確constchar*constp5;//L6錯誤,p5是常量,必須初始化

p1="wankang"; //L7錯誤,p1是常量,不可改p2="wankang";

//L8正確,p2是變量,可改p3="wankang";

//L9正確,p3是變量,可改p4="wankang"; //L10錯誤,p4是常量,不可改p1[0]='w';

//L11正確p2[0]='w'; //L12錯誤,*p2是常量,不可改p3[0]='w'; //L13錯誤,*p3是常量,不可改p4[0]='w'; //L14錯誤,*p4是常量,不可改

return0;}本例各錯誤的原因?2.6.2const、constexpr與指針【例2-12】const與指針的關(guān)系練習(xí)1、指出下面的錯誤

inti=-1; constintic=i; constint*pic=⁣ int*constcpi=⁣ constint*constcpic=⁣i=ic;pic=⁣cpi=pic;pic=cpic;cpic=⁣ic=*cpic;錯誤的有?2.6.2const、constexpr與指針 練習(xí)2、下面的聲明中,哪些是錯誤的?

inti; constintic; constint*pic; int*constcpi; constint*constcpic;2.6.2const、constexpr與指針投屏:錯誤的有1、概念與功能在定義引用時,可以用const進行限制,使它成為不允許被修改的常量引用。inti=9,int&rr=i;const int&ir=i;rr=8;ir=7; //錯誤,ir為const2.6.3

const與引用2、用常數(shù)或表達式初始化#include<iostream.h>voidmain(){ inti=10; constdouble&x=23+23+i; cout<<"x="<<x<<endl;}對于形如T&x的普通引用,必須用一個類型T的左值初始化x。對于一個形如constT&x的初始化,則不必是一個左值,甚至可以不是T類型的,其處理過程度如下:1、首先,如果需要,將應(yīng)用T的類型轉(zhuǎn)換。2、而后將結(jié)果存入一個類型T的臨時變量。3、最后將此臨時變量用作初始式的值。56臨時內(nèi)存56.0056.00x轉(zhuǎn)換成double類型將X作為此臨時內(nèi)存的別名,直到X“死亡”2.6.3

const與引用

doubledval=1024; constint&ri=dval; dval=90; cout<<"dval="<<dval<<endl; cout<<"ri="<<ri<<endl;ri=90;//錯誤,修改常量程序輸出結(jié)果:

dval=90ri=1024whyriis1024?編譯器將此定義轉(zhuǎn)換成類似如下的代碼:inttemp=dval;constint&ri=temp;

對dval的修改不會影響到temp,所以ri的值不會因dval而變動。2.6.3

const與引用3、用變量初始化const引用2.6.4頂層const與底層const1、概念指針實際上定義了兩個對象:指針本身和它所指的對象。這兩個對象都可以用const進行限定,當(dāng)指針本身被限定為常量時,稱指針為頂層const;當(dāng)所指的對象被限定為常量,而指針本身未被限定時,稱指針為底層const;當(dāng)指針和所指對象兩者都被限定為常量時,則指針為頂層const,所指對象為底層const。例如:inti=0;constintic=32;int*constp1=&i; //p1為頂層constconstint*p2; //P2為底層constconstint*constp3=⁣//p3為頂層const,(*p3)為底層const2.6.4頂層const與底層const2、概念延伸一般地,頂層const其實是指不可被修改的常量對象,此概念可以推廣到任意的數(shù)據(jù)類型定義的常量對象都是頂層const。底層const則與指針和引用這樣的復(fù)合類型定義有關(guān),其中指針比較特殊,既可以頂層const,也可能是底層const。而所有聲明為const的引用都是底層const??偨Y(jié):指向常量的指針(指針本身非常量)和常量引用是低層const,其它都是頂層指針。inti=3;constdoubled=9.0//ic為頂層constconstintic=32;//ic為頂層constconstint&ri=i;//ri為底層constconstint&ric=ic;//ric為底層const2.6.4頂層const與底層const3、應(yīng)用(1)復(fù)制頂層const不受影響。由于執(zhí)行復(fù)制時不影響被復(fù)制對象的值,因此它是否為常量對復(fù)制沒有影響。例如,inti=3;constdoubled=9.0 //ic為頂層constconstintic=32; //ic為頂層constconstint&ric=ic;constint*p2;//P2為底層constconstint*constp3=⁣i=ic; //正確:ic是一個頂層const,對此操作無影響

p2=p3;//正確:p2和p3指向的對象類型相同,p3頂層const部分不影響

2.6.4頂層const與底層const(2)底層cons的復(fù)制是受限制的。要求拷入和拷出的對象有相同的底層const或者能夠轉(zhuǎn)換為相同的數(shù)據(jù)類型,一般而言,非常量能夠轉(zhuǎn)換成常量,反之則不行。例如,針對前面的語句組,執(zhí)行下面的復(fù)制操作。inti=3;constdoubled=9.0; //ic為頂層constconstintic=32; //ic為頂層constconstint&ric=ic;constint*p2; //P2為底層constconstint*constp3=⁣p2=p3; //正確:p2為底層const,p3是頂層也是底層const,且類型同。p2=&i; //正確:p2為底層const,&i為int*,且能轉(zhuǎn)換成constint*p2=⁣ //正確:p2為底層const,&ic為constint*p2=&ric; //正確:p2的ri為相同類型的底層constint*p=p3; //錯誤:p3包括底層const定義,而p沒有

constint&r2=i; //正確:r2為底層const,而i可以轉(zhuǎn)換成底層constint&r=ic; //錯誤:r為底層const,而ic為頂層const2.6.4頂層const與底層const(3)常見應(yīng)用——限定函數(shù)參數(shù)在C++庫函數(shù)中,常見到許多函數(shù)的形參用const限定,可以簡單理解為:提供了更多的調(diào)用形式!因為,(1)用const限定的參數(shù),可以接受const和非const類型的參數(shù)(非const可以轉(zhuǎn)換成const)(2)若函數(shù)參數(shù)為非const類型,則不能接受const類型的實參。小結(jié):const與引用、指針底層const頂層constCode::Block(Review案例)Const*intp;int*q=newint(8);Int*constp1=q;Constint*constp2=q;Intr=0;Constint&rr=I;推廣:底層const外,所有其它的const對象都是頂層const復(fù)制(賦值和函數(shù)參數(shù)傳遞時,拷入、拷出要求。非常量能夠轉(zhuǎn)換為常量。為同類型的const,忽略頂層constintj=9;constinti=0;Intf1(int&x);f1(j)f1(i)Intf2(constint&x);f2(j)f2(i)intp1(int*x)p1(&j)p1(&i)intp2(constint*x)p2(&j)p2(&j)intp3(constint*constx)紅色函數(shù)調(diào)用是錯誤的!Intf1(intx);f1(j)f1(i)Intf2(constintx);f1(j)f1(i)intp1(int*x)Intp3(constint*constx)p2(&j)p2(&j)紅色函數(shù)調(diào)用是錯誤的!2.7auto、decltype

和decltype(auto)1.a(chǎn)uto和decltype的功能從變量或表達式中自動推斷出數(shù)據(jù)類型。2.a(chǎn)uto和decltype的區(qū)別變量初始化:兩者都用從表達式結(jié)果推斷出的類型定義變量auto會用表達式結(jié)果初始化定義的變量,decltype不初始化變量const忽略問題auto只保留底層指針的const,忽略其它類型的const(表達式的頂層const,引用的const,頂層指針const);Decltype為原類型推斷,保留所有的const,不忽略任何const,其結(jié)果是定義與變量相同類型的變量(包括頂層const和引用在內(nèi))變量表達式推導(dǎo)并定義變量2.7auto、decltype

和decltype(auto)3.a(chǎn)uto類型推斷(1)定義語法auto變量名1=表達式1,變量名2=表達式2……;inti;constint*constp=&i;constintic=i,&rc=ic;autox=3+8;//intx=3+8;autoc='s';//charc=’s’autos="abcde";//constchar*s=”abcde”autoz=x+3.8;//doublez=x+3.8autopi=&i;//int*pi=&iautopc=⁣//constint*pc=&ic,對常量對象取地址是底層constautorrc=rc;//intrrc,忽略引用的constautoric=ic;//intric,忽略頂層constautopp=p;//constint*p,忽略頂層constauto會忽略頂層const和引用的const,指針底層const則會保留下來;2.7auto、decltype

和decltype(auto)(2)auto定義引用用auto設(shè)置引用類型時,初始值中的頂層const會被保留,而引用字面常量時需要指定為const引用。inti;constintic=I;auto&ri=i;//int&ri=iauto&rc=ic;//constint&rc=ic,頂層constauto&r0=4.3//錯誤,不能夠?qū)⒎浅=壎ǖ匠?shù)constauto&r1=4.3//正確2.7auto、decltype

和decltype(auto)(3)auto注意事項auto需要根據(jù)表達式的值推斷數(shù)據(jù)類型,因此要求在用auto定義變量時,表達式的類型是清楚而明確的。一條auto可以同時定義多個變量,但數(shù)據(jù)類型只能有一種。autox=3,y=12,z=30;//正確,x,y,z為int類型autoa=3,b=3.2;//錯誤,a和b的類型不同2.7auto、decltype

和decltype(auto)3.decltype類型推斷(1)語法deltype(表達式1)變量=表達式2;deltype((表

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論