《面向对象程序设计C++》课件1第2章 面向过程程序设计概述_第1页
《面向对象程序设计C++》课件1第2章 面向过程程序设计概述_第2页
《面向对象程序设计C++》课件1第2章 面向过程程序设计概述_第3页
《面向对象程序设计C++》课件1第2章 面向过程程序设计概述_第4页
《面向对象程序设计C++》课件1第2章 面向过程程序设计概述_第5页
已阅读5页,还剩150页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2023/11/121第2章面向过程程序设计概述本章学习要点从C语言到C++的发展历程简单的C++程序C++在面向过程程序设计方面对C语言的扩充C++的输入输出、数据类型、常变量及指针C++的引用、函数、名字空间、字符串变量、复数变量C++程序的编写和实现2023/11/122本章学习目标了解从C语言到C++的发展历程对简单的C++程序有整体的感性认识掌握C++在面向过程程序设计方面对C的扩充掌握C++的输入输出、数据类型、常变量及指针掌握C++的引用、函数、名字空间、字符串变量、复数变量熟悉C++程序的编写和实现流程第2章面向过程程序设计概述2023/11/123§2.1从C语言到C++C语言到C++的发展历程C++3.0C++2.0C++1.0带类的CCC++4.0ANSIC++89年,增加类的多继承91年,增加模板增加异常处理、名字空间、运行时类型识别97年,美国C++标准正式发布2023/11/124下面看几个简单的C++程序【例2-1】在屏幕上输出一行字符“Welcometo

C++!”。#include<iostream> //包含头文件命令usingnamespacestd; //使用名字空间stdintmain(){

cout<<"WelcometoC++!"<<endl;//输出字符串到屏幕

return0;

//main函数返回0至操作系统}§2.2简单C++程序标准C++程序和C程序的不同:①main函数的返回值为整型②注释符://③使用cout输出④包含头文件iostream⑤名字空间注意【例2-2】通过函数求两个整数a和b中的较大者。

#include<iostream> //包含头文件命令usingnamespacestd; //使用名字空间stdintmyMax(intx,inty){returnx>y?x:y;}//求两数中的大者函数Maxintmain(){ inta,b;//定义两个整型变量a和b cout<<"Pleaseentertwointegers:"<<endl;

cin>>a>>b; //等待用户从键盘输入数据

cout<<"Thebiggeris"<<myMax(a,b)<<endl;

return0; }2023/11/125§2.2简单C++程序C++的函数和C语言的函数非常相似函数的使用仍然需要先声明后使用。如果函数定义在函数调用之后,则必须在前面声明函数原型注意2023/11/126

#include<iostream> //包含头文件命令usingnamespacestd;//使用名字空间stdintmain(){ inta,b;//定义两个整型变量a和b cout<<"Pleaseentertwointegers:"<<endl;

cin>>a>>b; //等待用户从键盘输入数据

intmyMax(intx,inty);

//Max函数原型声明

cout<<"Thebiggeris"<<myMax(a,b)<<endl;

return0; }intmyMax(intx,inty){returnx>y?x:y;}§2.2简单C++程序变量可以在程序的任何地方定义,但要在使用前2023/11/127§2.2简单C++程序【例2-3】声明一个关于人的类Person,人的信息包括姓名、性别、年龄,程序运行后,人可以输入自己的信息,也可以显示自己的信息。#include<iostream> //包含头文件命令usingnamespacestd;//使用名字空间stdclassPersonintmain(){{…………};return0;}2023/11/128§2.2简单C++程序classPerson //类的声明{public: //以下为类的公用成员函数

voidsetInfo()//公用成员函数setInfo

{cout<<"Inputinfotoname,sex,age:\n";

cin>>name>>sex>>age;}

voidshow()//公用成员函数show

{cout<<"name:"<<name;

cout<<"sex:"<<sex;

cout<<"age:"<<age<<endl;}

private://以下为类的私有数据成员

charname[20]; //私有数据成员name charsex[2]; //私有数据成员sex intage;//私有数据成员age};

//类声明结束,此处必须有分号

2023/11/129§2.2简单C++程序intmain() //main函数{

//定义Person类的两个对象person1,person2

Personperson1,person2;

person1.setInfo();

//对象person1信息输入

person2.setInfo();//对象person2信息输入

person1.show();//对象person1信息输出

person2.show();//对象person2信息输出

return0;}2023/11/1210注意:类的声明和对象的定义的语法形式。类中的成员分为数据成员和成员函数,成员的可见性分为3种:公用

、私有、受保护。类的概念的理解:类是一种用户自定义数据类型,它是不占用实际存储空间的。对象的理解:对象是类类型的变量,系统会为对象分配内存空间。§2.2简单C++程序2023/11/1211§2.3C++对C语言的扩充在输入输出方面的扩充对数据类型的扩充常变量在指针方面的扩充引用的概念在函数方面的扩充名字空间的概念字符串变量复数变量本章重点2023/11/1212§2.3.1C++的输入输出C语言输入输出的实现通过输入输出库函数实现C语言的输入输出存在着格式复杂、无法保证安全性、无法对自定义类型整体输入输出等缺点

C++对C输入输出的扩充C++的输入/输出(I/O)流类库“流”的思想cout、cin对象,<<、>>运算符2023/11/1213§2.3.2

C++对C语言数据类型的扩展新增数据类型数据类型基本类型构造类型指针类型引用类型空类型(void)字符型(char、wchar_t、char16_t、char32_t)(signedchar、short、int、long、longlong)整型单精度型(float)双精度型(double)长双精度型(longdouble)浮点型枚举类型数组类型结构体类型共用体类型类类型布尔型(bool)有符号整型无符号整型(unsignedchar、unsignedshort、unsignedint、unsignedlong、unsignedlonglong)功能进行了扩充2023/11/1214C++对C语言的结构体、共用体、枚举等自定义数据类型做了扩充。§2.3.2C++对C语言数据类型的扩展2023/11/1215struct

Student{intnum;charname[20];charsex;voiddisplay(){cout<<"num="<<num<<endl;cout<<"name="<<name<<endl;cout<<"sex="<<sex<<endl;}};§2.3.2C++对C语言数据类型的扩展2023/11/1216struct

Student{private:intnum;charname[20];charsex;public:voiddisplay(){cout<<"num="<<num<<endl;cout<<"name="<<name<<endl;cout<<"sex="<<sex<<endl;}};Studentstud1,stud2;§2.3.2C++对C语言数据类型的扩展2023/11/1217在C++中用结构体类型名、共用体类型名、枚举类型名定义变量时,不必在类型名前加上前缀struct、union、enum。§2.3.2C++对C语言数据类型的扩展2023/11/1218structstudent{charID[15];charname[20];intage;};unionxy{intx;chary;};enumcolor{black,white,red}studentstud;xyx1;colorcol;structstudentstud;unoinxyx1;enumcolorcol;C语言C++§2.3.2C++对C语言数据类型的扩展2023/11/1219§2.3.3常变量直接常量和符号常量使用符号常量需要注意的问题:运行时不分配内存单元符号常量没有类型,在编译时不进行类型检查注意替换后的表达式和预想的表达式是否一致intx=1,y=2;#definePI3.14159#defineRx+ycout<<PI*R*R<<endl;输出语句输出的并不是3.14159*(x+y)*(x+y),而是3.14159*x+y*x+y。2023/11/1220§2.3.3常变量为了使常量也能像变量那样进行类型检查,C++提供了用const定义常变量的方法定义常变量的语法:

constfloatPI=3.14159;注意:常变量要在定义的同时进行初始化,可以是具体的数值,也可以是表达式。2023/11/1221§2.3.3常变量C++提供的变量初始化的几种形式。例如,想定义整型变量x并初始化为1,以下的4条语句都可以实现:(1)intx=1;(2)intx={1};(3)intx(1);(4)intx{1};其中,花括号形式的列表初始化是C++11标准新引入的,并得到全面应用。当用于内置类型的变量时,这种初始化形式有一个重要特点:如果初始值存在丢失信息的风险,编译器将报错。longdoubleld=3.1415926536;inta{ld},b={ld};//错误:转换未执行,因为存在丢失信息的风险intc(ld),d=ld;//正确:转换执行,且确实丢失了部分值2023/11/1222【例2-4】利用常变量计算圆的面积。

#include<iostream>usingnamespacestd;intmain(){

constfloatPI{3.14159};

//定义常变量

floatradius{0};

cout<<"Pleaseenterradius:";

cin>>radius;

cout<<"Theareaofcircleis:"<<PI*radius*radius<<endl;

return0;}§2.3.3常变量注意const的位置,一般见到的const的位置可能在类型的前面,但是const也可以在变量名前面,并且两者的含义完全相同。注意

floatconstPI{3.14159};//定义常变量2023/11/1223§2.3.3常变量由于定义常变量的关键字为const,故常变量也被称为const变量。可以在程序的任何位置定义常变量。需要注意的是,常变量在定义时必须进行初始化,可以用值对其初始化,也可以使用表达式。使用表达式时,系统会先计算出表达式的值,然后再将值赋给常变量。constinti;//错误:未对i初始化constintj{10};//正确:编译时初始化,j也称为编译期常变量constintk{get_size()};//正确:运行时初始化,k也称为运行期常变量,get_size()为自定义函数constcharc{"hello"};//错误:invalidconversionfrom'constchar*'to'char'2023/11/1224§2.3.3常变量const与constexpr:关键字constexpr于C++11中引入并于C++14中得到改善。它表示常量表达式(指值不会改变并且在编译过程就能得到计算结果的表达式)。与const相同,它可应用于变量,任何代码试图修改该值,均将引发编译器错误。与const不同,constexpr也可应用于函数和类构造函数(分别在2.3.6节和3.12节介绍)。2023/11/1225§2.3.3常变量用constexpr定义变量的方法:constexprfloatx{42.0};//42.0是常量表达式constexprfloaty{108};//108是常量表达式constexprintsize{size()};//只有当size是一个constexpr函数时,才是一条正确的声明语句constexprinti;//错误,未对i初始化intj{0};constexprintk{j+1};//错误,j不是一个常量表达式

const侧重于值不变,constexpr侧重于编译期就确定值。2023/11/1226§2.3.4指针指针指针是一个重要概念,如果使用得当可以使程序高效、简洁、紧凑。如果对指针掌握不牢固,编程则会出现意想不到的错误指针是内存单元的地址

经常所讲的指针是指针变量的简称,是用来存放指针(地址)的变量。

本节重点讨论C++中使用指针需要注意的地方2023/11/1227§2.3.4.1空指针空指针空指针表示“未分配”或者“尚未指向任何地方”的指针空指针一般用来判断内存分配是否成功注意:“空指针”与“野指针”的区别在指针上下文中的常数0被编译成空指针程序员更常使用符号常量NULL来表示空指针C++11引入新的关键字来代表空指针常数:nullptr,将空指针和整数0的概念拆开。

未初始化的指针2023/11/12燕京理工学院28【例2-5】指针与0。#include<iostream>usingnamespacestd;intmain(){

intx=100;//定义整型变量x并初始化为100

int*p=0;//定义空指针p //*p=50;

//此语句编译出错,不能使用空指针 p=&x;

//使指针p指向变量x if(p!=0)

//判断指针p是否为空指针

cout<<"*p="<<*p<<endl;//输出变量x的值

int*q;//定义野指针q//*q=50;

//编译通过,但程序执行时出现内存访问冲突

q=&x;//使指针q指向变量x

if(q!=0)//判断指针q是否为空指针

cout<<"*q="<<*q<<endl;//输出变量x的值return0;}int*p=NULL;int*p=nullptr;2023/11/12燕京理工学院29【例2-5】指针与0。#include<iostream>usingnamespacestd;intmain(){intx{100};//定义整型变量x并初始化为100

int*p{nullptr};//定义空指针p//*p{50};//此语句编译出错,不能使用空指针

p=&x;//使指针p指向变量xif(p!=nullptr)//判断指针p是否为空指针

cout<<"*p="<<*p<<endl;//输出变量x的值

int*q;//定义野指针q//*q{50};//不同的C++编译器,处理结果不同,也被注释掉了

q=&x;//使指针q都指向变量xif(q!=nullptr)//判断指针q是否为空指针

cout<<"*q="<<*q<<endl;//输出变量x的值

return0;}2023/11/1230§2.3.4.2指针与constint*p=nullptr;constint*p=nullptr;intconst*p=nullptr;指向const变量的指针int*constp=nullptr;const指针2023/11/12燕京理工学院31§2.3.4.2指针与const【例2-6】指向const变量的指针。include<iostream>usingnamespacestd;intmain(){constint*p=nullptr;//定义指向const变量的指针p constinta=10;//定义常变量a p=&a;//指针p指向a cout<<"*p="<<*p<<endl;//输出p所指向单元的内容

intb=100;//定义普通变量b p=&b;//指针p指向b cout<<"*p="<<*p<<endl;//输出p所指向单元的内容

//*p=200;

//错误,不能通过p修改p所指向单元的内容

b=200; cout<<"*p="<<*p<<endl;//输出p所指向单元的内容

return0;}通过本例可以看到可以改变指向const变量的指针的指向,但是不能通过指针修改指针指向单元的内容。(1)如果一个变量已被声明为常变量,只能用指向const变量的指针指向它,而不能用一般的(指向非const型变量的)指针去指向它。(2)指向常变量的指针除了可以指向常变量外,还可以指向普通变量。此时,可以通过指针访问该变量,但不能通过指针改变该变量的值。注意2023/11/1232§2.3.4.2指针与const【例2-7】const指针。#include<iostream>usingnamespacestd;intmain(){inta=10;//定义普通变量a intb=100;//定义普通变量b int*constp=&a;//定义const指针p并初始化指向a cout<<"*p="<<*p<<endl;//输出p所指向单元的内容

//p=&b;//错误,不能改变const指针p的指向 *p=100;//通过指针修改p所指向单元的内容

cout<<"*p="<<*p<<endl;//输出p所指向单元的内容

return0;}通过本例可以看到可以改变const指针指向单元的内容,但是不能改变const指针的指向。2023/11/1233§2.3.4.2指针与const【例2-8】指向const变量的const指针。#include<iostream>usingnamespacestd;intmain(){ inta=10; intb=100;constint*constp=&a;

//定义指向const变量的const指针p

cout<<"*p="<<*p<<endl;//输出p所指向单元的内容

//p=&b;//错误,不能改变指针p的指向

//*p=100;//错误,不能改变p所指向单元的内容

return0;}对于指向const变量的const指针,既不能改变指针指向单元的内容,也不能改变指针的指向。2023/11/1234§2.3.4.2指针与const[小结]指针和const的关系比较复杂,const有两个位置,可形成三种指针:constint*p=nullptr;intconst*p=nullptr;指向const变量的指针int*constp=nullptr;const指针2023/11/1235§2.3.4.2指针与const[小结]指针和const的关系比较复杂,const有两个位置,可形成三种指针:constint*constp=nullptr;intconst*constp=nullptr;指向const变量的const指针:2023/11/1236§2.3.4.3指针与constexpr在定义一个指针时,可以加constexpr关键字修饰,这样的指针也称为constexpr指针。注意:constexpr仅仅对指针有效,与指针所指的对象无关。由于constexpr指针是编译期常量,其指向由其定义时的初始值确定后不允许再改变,把其初始值设置为nullptr或者0,只是从语法层面上允许这样做,在实际编程中没有意义。定义于所有函数体之外的变量其地址固定不变,能用来初始化constexpr指针。C++允许函数定义一类有效范围超出函数本身的变量,如局部静态变量,这类变量和定义在函数体之外的变量一样也有固定地址,因此,constexpr指针也能指向这样的变量。2023/11/1237§2.3.4.3指针与constexpr【例2-9】constexpr指针的定义与使用。#include<iostream>usingnamespacestd;inti=10;//定义全局整型变量iconstexprintj=20;//定义常量表达式变量jintmain(){//定义指向变量的constexpr指针p,并使其指向全局整型变量iconstexprint*p=&i;

//定义指向常变量的constexpr指针q,并使其指向常量表达式变量jconstexprconstint*q=&j;……}2023/11/1238§2.3.4.3指针与constexprintmain(){……

//通过constexpr指针p输出变量i的值

cout<<"i="<<*p<<endl;

//通过constexpr指针q输出常量表达式变量j的值

cout<<"j="<<*q<<endl;staticcharx='A';//定义局部静态变量x

//定义指向变量的constexpr指针px,并使其指向局部静态变量xconstexprchar*px=&x;

//通过constexpr指针px输出局部静态变量x的值

cout<<"x="<<*px<<endl;return0;}2023/11/1239§2.3.4.4void指针void在作为函数类型和参数类型时为空类型,表示没有返回值或参数。void修饰指针时称为“无类型指针”,表示该指针可以指向任意类型的变量。虽然void指针可以指向任意类型的数据,但是在使用void指针时必须对其进行强制类型转换,转换成它所指向单元的实际类型,然后才可以使用。

2023/11/1240§2.3.4.4void指针【例2-10】void指针的定义与使用。#include<iostream>usingnamespacestd;intmain(){intx=100; void*p=&x;//定义void指针p指向xint*q=nullptr;//定义整型指针q

//cout<<"*p="<<*p<<endl;

//错误cout<<"*p="<<*(int*)p<<endl;//正确

//q=p;

//错误q=(int*)p;//正确cout<<"*q="<<*q<<endl;//输出指针q指向单元的内容return0;}2023/11/1241§2.3.4.4void指针为什么要使用void指针因为void指针可以指向任意类型的数据,所以使用void指针时把void指针所指向的数据给抽象化了,这样可以增加程序的通用性使用void指针的两个例子void*memcpy(void*dest,constvoid*src,size_tlen);void*malloc(unsignedintsize);2023/11/1242§2.3.4.5new和deleteC语言的动态内存管理malloc()和free()函数主要缺点函数的返回值是void*类型分配内存单元时根据参数size的值来分配,无法检查错误分配到的内存单元无法初始化C++中使用new和delete运算符进行动态内存管理P31最后2023/11/1243【例2-11】使用new动态分配整型内存单元。#include<iostream>usingnamespacestd;intmain(){int*p=nullptr; //定义整型指针p

//用new申请可以存放一个整型数据的内存单元,将申请到的内存首地址存入指针变量pp=newint;

//输出指针p指向单元的内容cout<<"*p="<<*p<<endl;return0;}§2.3.4.5new和delete2023/11/1244【例2-12】使用new和delete动态管理内存单元。#include<iostream>usingnamespacestd;intmain(){int*p=nullptr;p=newint;

cout<<"*p="<<*p<<endl;

deletep;p=nullptr;

return0;}通过new运算得到的内存单元是不会自动释放的,必须通过delete运算去释放注意§2.3.4.5new和delete2023/11/1245申请内存空间并进行初始化指针变量=new数据类型(初值);分配多个连续变量的存储空间使用new[]和delete[]指针变量=new数据类型[元素个数];delete[]指针变量;三种动态内存管理的方式:兼容C语言的malloc/free方式,单个变量的new/delete方式,多个变量的new[]/delete[]方式§2.3.4.5new和delete2023/11/1246§2.3.5引用引用就是某一变量的别名,对引用的操作与对变量直接操作完全一样引用的声明方式

类型标识符&引用名=目标变量名;2023/11/1247§2.3.5引用inta=20;int&b=a;20地址2000变量a引用b在声明一个引用时,引用前面的类型标识符是指目标变量的类型,且必须同时使之初始化,即声明它代表哪一个变量.2023/11/1248【例2-13】使用引用访问变量。#include<iostream>usingnamespacestd;intmain(){intx=100; //定义整型变量xint&rx=x; //定义变量x的引用rxcout<<"rx="<<rx<<endl; //输出引用rx的内容

rx=200; //给引用rx赋值

cout<<"x="<<x<<endl; //输出变量x的内容

return0;}程序运行结果如下:rx=100x=200§2.3.5引用2023/11/1249关于引用的简单说明(1)引用并不是一种独立的数据类型,声明引用时必须指定其代表某一类型的实体(如变量、类对象),即对它初始化。inta;int&b=a;int&b;floata;int&b=a;××2023/11/1250(2)引用与其所代表的变量共享同一内存单元,系统并不为引用另外分配存储空间。inta=3;int&b=a;cout<<&a<<"

"<<&b<<endl;关于引用的简单说明2023/11/1251inta=3;int&b=a;//声明b是整型变量的别名int&c=b;//声明c是整型引用b的别名(3)对引用的初始化,可以用一个变量名,也可以用另一个引用。如:补充:关于引用的简单说明2023/11/1252(4)引用在初始化后不能再被重新声明为另一变量的别名。inta=3,b=4;int&c=a;int&c=b;//企图重新声明c为整型变量b的别名×补充:关于引用的简单说明2023/11/1253(5)当&a的前面有类型符时(如int&a),它必然是对引用的声明;如果前面没有类型符时(p=&a),此时的&是取地址运算符。inta=3,b=4;int&c=a;int*p=&b;补充:关于引用的简单说明2023/11/1254实际上,在C++程序中很少使用独立变量的引用,如果要使用某一个变量,就直接使用它的原名,没有必要故意使用它的别名。前面举的例子只是为了说明引用的特征和基本的用法。C++之所以增加“引用”,主要是利用它作为函数参数,以扩充函数传递数据的功能关于引用的简单说明2023/11/1255在C语言中,函数的参数传递有以下两种情况:(1)值传递:将变量名作为形参和实参。此时传递给形参的是实参变量的值,数据传递是单向的,在函数执行期间形参值发生变化并不回传给实参。(2)地址传递:2023/11/1256(2)地址传递:形参是指针变量,实参是变量的地址。函数调用时,形参指向实参变量单元,数据传递是双向的。2023/11/1257【例2-14】编写一个函数,交换两个整型变量的值。(1)值传递:教材4310x20y1020xy20102023/11/1258(2)地址传递:传递变量的地址(指针)【例2-14】编写一个函数,交换两个整型变量的值。10x20y*x*y20102023/11/1259(3)引用传递:【例2-14】编写一个函数,交换两个整型变量的值。2023/11/1260#include<iostream>usingnamespacestd;voidchange(int&x,int&y){inttmp;tmp=x;x=y;y=tmp;}intmain(){intx=10,y=20;cout<<"交换前:x="<<x<<",y="<<y<<endl;change(x,y);

cout<<"交换后:x="<<x<<",y="<<y<<endl;return0;}

别名x10变量x20变量y

别名y2023/11/1261对引用的进一步说明(1)不能建立数组的引用。

“引用”只能是变量或对象的引用。数组是具有某种类型的数据的集合,其名字表示该数组的起始地址而不是一个变量。所以不能建立数组的引用。charc[6]=“hello”;char&rc=c;╳2023/11/1262(3)可以将变量的引用的地址赋给一个指针,此时指针指向的是原来的变量,如

inta=3;int&b=a;int*p=&b;

由于引用不是一种独立的数据类型,不能建立指向引用类型的指针变量:int&*p=&a;

对引用的进一步说明2023/11/1263(4)可以建立指针变量的引用,如

inti=3;int*p=&i;int*&pt=p;对引用的进一步说明2023/11/1264(5)可以用const对引用加以限定,不允许改变该引用的值。如

inti=5;constint&a=i;a=3;

但可以

i=3╳√对引用的进一步说明2023/11/1265利用常引用作为函数形参,既能提高程序的执行效率,又能保护传递给函数的数据不在函数中被改变,达到保护实参的目的引用型参数应该在能被定义为const的情况下,尽量定义为const。注意对引用的进一步说明voidshow(constint&x){x=8;cout<<“x=“<<x<<endl;}2023/11/1266(6)可以用常量或表达式对引用进行初始化,但此时必须用const作声明。如

inta=3;constint&b=a+3;√

inttemp=a+3;constint&b=temp;用这种方式不仅可以用表达式对引用进行初始化,还可以用不同类型的变量对之初始化。对引用的进一步说明2023/11/1267

doubled=3.14159;constint&a=d;inttemp=d;constint&a=d;╳对引用的进一步说明不用const,则会发生错误2023/11/1268(7)constexpr引用在声明一个引用时,可以加constexpr关键字修饰,这样的引用我们也称它为constexpr引用。需要注意的是,尽管引用能声明成constexpr,但它的初始值受到严格限制:它只能是存储于某个固定地址中的对象的引用,而不能像const引用那样,用常量或表达式对其初始化。定义于所有函数体之外的对象其地址固定不变,能用来初始化constexpr引用。同样,允许函数定义一类有效范围超出函数本身的变量(即局部静态变量),这类变量和定义在函数体之外的变量一样也有固定地址。因此,constexpr引用能绑定到这样的变量上。对引用的进一步说明2023/11/1269(8)引用作为函数的返回值【例2-15】引用作为函数的返回值。#include<iostream>usingnamespacestd;//此函数的返回值为对参数x和y中大者变量的引用int&myMax(int&x,int&y){ return(x>y)?x:y;}对引用的进一步说明2023/11/1270引用作为函数的返回值【例2-15】引用作为函数的返回值。intmain(){inta=2,b=3;cout<<"a="<<a<<"b="<<b<<endl;myMax(a,b)=4;

/*由于函数的返回值为引用,所以可以为函数赋值,为函数赋的值实际赋给了两个参数中的大者,所以a的值为2,b的值为4*/cout<<"a="<<a<<"b="<<b<<endl;return0;}对引用的进一步说明2023/11/12燕京理工学院71引用作为函数的返回值引用作为函数的返回值的补充示例。classstring{public:……string&operator=(conststring&right);

//重载赋值运算符string&operator+=(conststring&right);intcompare(conststring&)const;//字符串比较private:unsignedbuflen;char*buffer;};对引用的进一步说明2023/11/1272指针与引用的区别:(1)从内存分配上看:指针变量需要分配内存区域,而引用不需要分配内存区域。(2)指针可以有多级,但是引用只能是一级(int**p;合法而int&&a是不合法的);(3)指针的值可以为nullptr,但是引用的值不能为nullptr,并且引用在定义的时候必须初始化;(4)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不能再改变了;(5)指针和引用的自增(++)运算意义不一样。对引用的进一步说明2023/11/1273引用以简略的方式取代了某些条件下指针的作用,尤其适合函数的参数传递。但有些时候,引用还是不能替代指针,这样的情况主要包括以下几种。(1)如果一个指针所指向的对象,需要用分支结构加以确定,或者在中途需要改变它所指向的对象,那么在它初始化之后需要为它赋值,而引用只能在初始化时指定被引用的对象,所以不能胜任。对引用的进一步说明2023/11/1274引用以简略的方式取代了某些条件下指针的作用,尤其适合函数的参数传递。但有些时候,引用还是不能替代指针,这样的情况主要包括以下几种。(2)有时一个指针的值可能是空指针,例如当把指针作为函数的参数类型或返回类型时,有时会用空指针表达特定的含义,而没有空引用之说,这时引用不能胜任。对引用的进一步说明2023/11/1275引用以简略的方式取代了某些条件下指针的作用,尤其适合函数的参数传递。但有些时候,引用还是不能替代指针,这样的情况主要包括以下几种。(3)由于没有函数引用,所以函数指针无法被引用替代。(4)用new动态创建的对象或数组,需要用指针来存储它的地址。(5)以数组形式传递大批量数据时,需要用指针类型参数(注意:参数中出现Ts[]与T*s是等价的)。对引用的进一步说明2023/11/1276面向过程的C++程序中的函数与C语言中的函数基本相同面向对象的C++程序中的函数有成员函数和公共函数之分下面主要讨论面向过程的C++程序中函数与C语言函数的区别§2.3.6函数2023/11/1277§2.3.6.1函数原型声明在函数尚未定义的情况下,先将函数的形式告诉编译系统,以便编译能够正常进行函数原型声明的语法形式有两种:(1)返回值类型函数名(参数类型1,参数类型2,...);(2)返回值类型函数名(参数类型1参数名1,参数类型2参数名2,...);函数原型声明和函数定义是不同的。函数原型声明不是一个独立的完整的函数单位,它仅仅是一条语句,因此在函数原型声明后面一定要加上分号。2023/11/1278§2.3.6.2函数默认参数在多次调用一个函数将实参传递给形参时,其中可能有一个或几个参数,它们传递进来的实参值多次相同在定义或声明函数时,给形参一个默认值,如果在调用时没有给该形参传递实参值,则使用默认值作为该形参的值;如果调用时给该形参传递了实参值,则使用实参的值作为该形参的值。2023/11/1279§2.3.6.2函数默认参数【例2-17】求两个或三个正整数中的最大值,使用带有默认参数的函数实现。#include<iostream>usingnamespacestd;intmain(){intmyMax(int,int,int=0);//带有默认参数的函数原型声明

inta=5,b=8,c=10; cout<<“Maxof(a,b)is:"<<myMax(a,b)<<endl;

cout<<“Maxof(a,b,c)is:"<<myMax(a,b,c)<<endl; return0;}//定义带有默认参数的函数intmyMax(inta,intb,intc=0){ if(a<b)a=b; if(a<c)a=c; returna;}2023/11/1280§2.3.6.2函数默认参数1.指定默认值参数默认值的位置:为了避免混淆,最好只在函数原型声明时指定默认值。2.当只有部分形参带有默认值时,带有默认值的参数必须放在形参表的右端。3.函数参数的默认值可以是数值,也可以是表达式(表达式中可以使用全局变量,也可以使用函数,但不可以是局部变量),只要该表达式能转换成形参所需的类型。4.当一个函数既是重载函数,又是带有默认参数的函数时,要注意不要出现二义性的问题注意2023/11/1281§2.3.6.2函数默认参数调用带有默认参数的函数时,实参的个数可以与形参的个数不同,对于实参未给出的,可以从形参的默认值中获得,利用这一特性,可以使函数的使用更加灵活。2023/11/1282§2.3.6.3函数与引用函数与引用联合使用主要有两种方式:1.函数的参数是引用

当使用引用作为函数的形参时,引用不是一个单独的变量,不需要在内存中分配存储单元,实参向形参传递的是变量的名字。使用引用作为函数的形参可以部分代替指针,降低了程序的复杂度,提高了程序的执行效率,同时也提高了程序的可读性。2.函数的返回值是引用

2023/11/1283§2.3.6.3函数与引用函数与引用联合使用主要有两种方式:2.函数的返回值是引用以引用作为函数的返回值是为了使函数可以作为左值而被赋值。函数的返回值为引用类型表示该函数的返回值是一个内存变量的别名。可以将函数调用作为一个变量来使用,可以为其赋值。2023/11/12燕京理工学院84引用作为函数的返回值示例:引用作为函数的返回值。classstring{public:……//重载赋值运算符string&operator=(conststring&right);string&operator+=(conststring&right);intcompare(conststring&)const;//字符串比较private:unsignedbuflen;char*buffer;};§2.3.5引用2023/11/1285§2.3.6.3函数与引用函数与引用联合使用主要有两种方式:2.函数的返回值是引用定义返回引用的函数时,注意不要返回对该函数内的自动变量的引用。否则,因为自动变量的生存期仅局限于函数内部,当函数返回时,自动变量就消失了,函数就会返回一个无效的引用。函数返回的引用是对某一个函数参数的引用,而且这个参数本身也是引用类型2023/11/1286§2.3.6.4函数与constconst修饰函数的参数const修饰函数的返回值const修饰整个函数2023/11/1287§2.3.6.4函数与constconst修饰函数的参数调用函数时用相应的值初始化const常量函数体按照const所修饰的部分进行常量化voidshow(constint&x){x=8;cout<<“x=“<<x<<endl;}2023/11/1288§2.3.6.4函数与constconst修饰函数的返回值用于二目操作符重载函数并产生新对象constFractionoperator*(constFraction&left,constFraction&right){returnFraction(left.numerator()*right.numerator(), left.denominator()*right.denominator());}返回值用const修饰可以防止允许这样的操作发生:Fractiona,b;Fractionc;(a*b)=c;2023/11/12燕京理工学院89§2.3.6.4函数与constconst修饰整个函数这种情况发生在类的成员函数时const的位置放在函数参数表的后面classstring{public:……intcompare(conststring&)const;//字符串比较private:unsignedbuflen;char*buffer;};2023/11/1290§2.3.6.5函数重载问题:求2个数的和。(分别考虑整数、浮点数的情况) intaddInt(inta,intb) {cout<<"Callintegeraddfunction."<<endl; returna+b; } floataddFloat(floata,floatb) {cout<<"Callfloataddfunction."<<endl; returna+b; }2023/11/1291§2.3.6.5函数重载C++允许在同一个作用域中用同一函数名定义多个函数,这些函数的参数个数或参数类型不相同,这些同名的函数用来实现同一类的操作。这就是函数的重载。即对一个函数名重新赋予它新的操作,使一个函数名可以多用。2023/11/1292§2.3.6.5函数重载【例2-19】使用add为函数名定义两个整数的加法函数和两个浮点数的加法函数. intadd(inta,intb)//整数加法的add函数定义 {cout<<"Callintegeraddfunction."<<endl; returna+b; } floatadd(floata,floatb)//浮点数加法的add函数定义 {cout<<"Callfloataddfunction."<<endl; returna+b; }2023/11/1293§2.3.6.5函数重载【例2-20】使用add作为函数名定义两个整数的加法函数和三个整数的加法函数。 intadd(inta,intb) {returna+b; } floatadd(floata,floatb,intc) {returna+b+c; }2023/11/1294§2.3.6.5函数重载(1)函数重载需要函数参数的类型或个数必须至少有其中之一不同,函数返回值类型可以相同也可以不同。但是,不允许参数的个数和类型都相同而只有返回值类型不同。从语法上来说,可以让两个或多个完全不相干的函数使用相同的函数名,进行重载,但是这样做使得程序的可读性下降,不建议这样做。使用同名函数进行重载时,重载函数在功能上应该相近或属于同一类函数。2023/11/1295§2.3.6.5函数重载(2)有些形参列表看起来不一样,但是实际上是相同的。顶层const不影响传入函数的对象,一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。例如:boolfind(int);boolfind(constint);//重复声明了boolfind(int)boolfind(int*);boolfind(int*const);//重复声明了boolfind(int*)2023/11/1296§2.3.6.5函数重载(3)如果形参是某种类型的指针或引用,则通过区分其指向或引用的是常量对象还是非常量对象可以实现函数重载。例如://对于接受引用或者指针的函数来说,对象是常量还是非常量对应的形参不同//下面这4个find是独立的重载函数boolfind(int&);//函数作用于int引用boolfind(consint&);//新函数,作用于常量int引用

boolfind(int*);//新函数,作用于指向int的指针boolfind(constint*);//新函数,作用于指向常量的指针2023/11/1297函数调用需要一定的时间和空间的开销。(保护现场/恢复现场,参数传递等)main函数fun函数调用fun函数结束①②③④⑤§2.3.6.6内置函数与constexpr2023/11/1298§2.3.6.6内置函数与constexpr由于调用函数时系统需要一定的时间和空间的开销(保护现场/恢复现场,参数传递等)。当函数体很小而又需要频繁调用时,运行效率与代码重用的矛盾变得很突出。这时函数的运行时间相对比较少,而函数调用所需的栈操作等却要花费比较多的时间。2023/11/1299C++解决这个问题的方法就是内置函数(inlinefunction),也称为内联函数或内嵌函数。系统在编译时将所调用函数的代码直接嵌入到主调函数中,这样在程序执行时就不会发生函数调用,而是顺序执行了。§2.3.6.6内置函数与constexpr【例2-21】使用内置函数实现求一个数的平方数。#include<iostream>usingnamespacestd;//内置函数square的原型声明inlinedoublesquare(doublex);intmain(){doublea=square(5); //调用函数squaredoubleb=square(2.0+8.0); //调用函数squarecout<<"a="<<a<<",b="<<b<<endl;

……}//定义内置函数squareinlinedoublesquare(doublex){returnx*x;}2023/11/12100§2.3.6.6内置函数与constexprintmain(){……doublec=20.0;cout<<"c="<<c;

//调用函数square求c的平方数cout<<",csquared="<<square(c++)<<endl; //输出c变量的当前值cout<<"Nowc="<<c<<endl;

return0;}//定义内置函数squareinlinedoublesquare(doublex){returnx*x;}2023/11/12101§2.3.6.6内置函数与constexpr2023/11/121021.在声明内置函数时,关键字inline必须与函数定义体放在一起才能使函数成为内置函数,仅将inline放在函数声明前面不起任何作用。2.内置函数是一种“以空间换时间”的策略。3.对函数进行内置声明,只是程序员对编译系统的一个建议而非命令,并不一定只要声明为内置函数C++系统就一定会按内置函数去处理,系统会根据实际情况决定是否这样做。4.内置函数的机制适用于被调函数规模较小而又被频繁调用的情况。注意§2.3.6.6内置函数与constexpr2023/11/12103内置函数与用#define命令实现的带参宏定义有些相似,但不完全相同。§2.3.6.6内置函数与constexpr2023/11/12104用带参宏定义实现求平方值。#include<iostream>usingnamespacestd;#definepower(x)x*xintmain(){cout<<power(2)<<endl;cout<<power(1+1)<<endl;return0;}宏定义是在编译前由预处理程序对其预处理,它只作简单的字符置换而不作语法检查,往往会出现意想不到的错误。2023/11/12105用内置函数实现求平方值。#include<iostream>usingnamespacestd;inlineintpower(intx)//改用内置函数{returnx*x;}intmain(){cout<<power(2)<<endl;cout<<power(1+1)<<endl;return0;}自从有了内置函数,一般不再用#define带参宏定义了。2023/11/12106constexpr函数:指能用于常量表达式的函数。定义constexpr函数的方法与其他函数类似。constexprintnew_sz(){return42;}constexprintfoo=new_sz();§2.3.6.6内置函数与constexpr为了能在编译过程中随时展开,constexpr函数被隐式地指定为内置函数。2023/11/12107带参数的constexpr函数:constexprunsignedintscale(unsignedintcnt){returnnew_sz()*cnt;}当scale的实参是常量表达式,它的返回值也是常量表达式,反之则不然。intarr[scale(2)];//正确:scale(2)是常量表达式inti=2;//i不是常量表达式intarr2[scale(i)];//错误:scale(i)不是常量表达式§2.3.6.6内置函数与constexpr2023/11/12108constexpr函数的使用规则:①constexpr函数可以用在需求编译期间常量的上下文。在这种上下文中,如果你传递参数的值在编译期间已知,那么函数的结果会在编译期间计算。如果任何一个参数的值在编译期间未知,代码将不能通过编译。②如果用一个或者多个在编译期间未知的值作为参数调用constexpr函数,函数的行为和普通的函数一样,在运行期间计算结果。这意味着你不需要两个函数来表示相同的操作,一个为编译期常量服务,一个为所有的值服务。constexpr函数把这些事都做了。注意§2.3.6.6内置函数与constexpr2023/11/12109//pow是一个constexpr函数,永远不会抛出异常constexprintpow(intbase,intexp)noexcept;//

numConds:条件的数量,auto类型说明符实现让编译器去分析表达式所属的类型constexprautonumConds=5;//results有3^n个元素std::array<int,pow(3,numConds)>results注意§2.3.6.6内置函数与constexpr//运行期得到base的值autobase=readFromDB("base");//运行期得到exp的值autoexp=readFromDB("exponent");//在运行期调用powautobaseToExp=pow(base,exp);2023/11/12110//C++11constexprintpow(intbase,intexp)noexcept{

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论