版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第2章C++对C的扩充2.4
命名空间
2.8
动态内存的分配2.10
引用2.11
const修饰符2.13
C++中函数的新特性2.4命名空间
2.4.1为什么要引入命名空间
命名空间是随标准C++而引入的,用来防止全局空间内的命名冲突,即重名问题。大型应用系统常常由许多人来设计完成,命名冲突是一种潜在的危险,程序员必须细心地定义标识符,以保证名字的惟一性。
一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。例如,设Bill是X公司的员工,工号为123,而John是Y公司的员工,工号也是123。由于两人在不同的公司工作,可以使用相同的工号来标识而不会造成混乱,这里每个公司就表示一个独立的命名空间。如果两人在同一家公司工作,其工号就不能相同了,否则会发生混乱。2.4.1为什么要引入命名空间
这一特点是使用命名空间的主要理由。在大型的计算机程序中,往往会出现成百上千个标识符。命名空间提供了一种隐藏区域标识符的机制。通过将逻辑上相关的标识符组织成相应的命名空间,可使整个系统更加模块化。在编程语言中,命名空间是一种特殊的作用域,它包含了处于该作用域内的标识符,且本身也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持命名空间。2.4.1为什么要引入命名空间
花括号括起来的部分称声明块。声明块中可以包括:类、变量(带有初始化)、函数(带有定义)等。在域外使用域内的成员时,需加上名字空间名作为前缀,后面加上域操作符“::”
。这里添加了名字空间名称的成员名被称为限定修饰名。如:ns1::a,ns1::fun1()等等。最外层的名字空间域称为全局名字空间域(globalnamespacescope),即文件域。namespacens1{
floata,b,c;fun1(){……}}声明块2.4.2如何创建命名空间命名空间名2.4.2如何创建命名空间
名字空间域可分层嵌套,有分层屏蔽作用。例如:namespacen1{
namespacen2//名字空间嵌套
{
classmatrix{……}}}访问matrix,可写:n1::n2::matrix。namespacens1{
floata,b,c;fun1(){……}}声明块命名空间名2.4.3如何访问命名空间成员1.
使用域操作符直接访问2.使用using
声明3.使用using
指令访问命名空间成员,有三种方法:
ns1::an1::n2::matrix#include<iostream>usingnamespacestd;namespaceA{intx=1;}namespaceB{intx=2;}voidmain(){
inty=x;
inta=A::x;intb=B::x;cout<<a<<b<<endl;}//errorC2065:'x':undeclaredidentifier//OK例使用using声明可只写一次限定修饰名using声明以关键字using开头,后面是被限定修饰的名字空间成员名,例如:usingn1::n2::matrix;以后在程序中使用matrix时,就可以直接使用成员名,而不必使用限定修饰名。 2.使用using
声明#include<iostream>usingnamespacestd;namespaceA{intx=1;}namespaceB{intx=2;}voidmain(){
inty=x;
inta=A::x;intb=B::x;cout<<a<<b<<endl;}usingA::x;inta=x;例
使用using指示符,可以一次性地使名字空间中所有成员都可以直接被使用,比using声明更方便。
using指示符以关键字using开头,后面是关键字namespace,然后是名字空间名。3.使用using指示符usingnamespacestd;3.使用using指示符
标准C++库中的所有组件都是在一个被称为std的名字空间中声明和定义的。因此,在采用标准C++的平台上使用标准C++库中的组件,只要写上这个using指示符,就可以直接使用标准C++库中的所有成员。
注意:如果使用了名空间std,则在使用#include编译预处理命令包含头文件时,必须去掉头文件的扩展名.h,否则会出错。#include<iostream>usingnamespacestd;namespaceA{intx=1;}namespaceB{intx=2;}voidmain(){
inty=x;
inta=A::x;intb=B::x;cout<<a<<b<<endl;}例using
namespaceA;inta=x+y;inty;}
通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配。有些对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。
当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。2.8动态内存的分配与释放
在程序运行时可使用的内存空间称为堆(heap),堆内存就是在程序运行时获得的内存空间,在程序编译和连接时不必确定它的大小,它随着程序的运行过程变化,时大时小,因此堆内存是动态的,堆内存也称为动态内存。
new运算符用于申请所需的内存空间,返回指定类型的一个指针(常量,即内存空间首地址)。它的语法格式为:
指针变量=new
数据类型;其中,指针变量应预先声明,指针变量指向的数据类型与new后面的数据类型相同。若申请成功,则返回分配空间的首地址赋给指针变量;否则(如没有足够的内存空间)返回0(NULL一个空指针)。例如:
int*p;p=new
int;(20);系统为指针p开辟了一个用来保存int类型数据的内存空间(在申请时,也可以进行初始化)。new
运算符在C++中,申请和释放堆中分配的存贮空间,分别使用new和delete两个运算符来完成,其使用的格式如下:例如:
int*p;p=new
int[20];系统为指针p开辟了一个用来保存int类型数组的内存空间,数组中有20个元素。
也可以用new运算符申请一块保存数组的内存空间,即动态创建一个数组。格式为:指针变量=new
数据类型[数组大小];
其中,数组大小给出数组元素的个数,指针指向分配的内存空间首地址,指针的类型与new后的数据类型相同。new
运算符
当程序中不再使用由运算符new申请的某个内存空间时,可以用delete运算符释放它。它的语法格式为:delete
指针变量;delete
[常量]指针变量;
它的功能是释放由new申请到的内存空间。其中指针变量是指向需要释放内存空间的指针变量名字,并且delete只是删除动态内存空间,并不是将指针变量本身删除。常量可以省略,且不用考虑数组的维数。int*p1=new
int;int*p2=new
int[20];deletep1;delete[]p2;delete
运算符1.new
运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。2.一般定义变量和对象时要用标识符命名,称命名对象,而动态所创建的变量或对象称无名对象。堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式()来显式初始化。但不可对动态数组初始化3.指针变量=new
数据类型[数组大小];
请注意“数组大小”不是常量表达式,即它的值不必在编译时确定,可以在运行时确定。变量n在编译时没有确定的值,而是在运行中输入,按运行时所需分配堆空间,这一点是动态分配的优点,可克服数组“大开小用”的弊端,在表、排序与查找中的算法,若用动态数组,通用性更好。说明:4.动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。因此,一定要检查分配的内存指针是否为空,如果是空指针,则不能引用这个指针,否则将造成系统崩溃。说明:int*p=new
int[20];if(p!=NULL){…}else
{…}5.指针删除与堆空间释放。删除一个指针p;实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针。6.动态分配的变量或对象的生命期。无名对象的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(freestore)就是这个原因。但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错。
说明:7.内存泄漏(memoryleak)和重复释放。new与delete是配对使用的,delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。#include<iostream>usingnamespacestd;voidmain(){
intn;//定义数组元素的个数
int*p;cout<<"pleaseinputthelengthofthearray:";cin>>n;
if((p=new
int[n])==0){cout<<"can'tallocatemorememory,terminating."<<endl;
exit(1);}//检查动态分配内存,若不成功,退出系统
【例2.4】从堆内存中获取一个整型数组,赋值后并打印出来。(P19)
【例2.4】从堆内存中获取一个整型数组,赋值后并打印出来。(P19)
for(inti=0;i<n;i++)p[i]=i*2;cout<<"Nowoutputthearray:"<<endl;
for(i=0;i<n;i++)cout<<p[i]<<"";cout<<endl;
delete[]p;//释放内存空间}Pleaseinputthelengthofthearray:6Nowoutputthearray:0246810
2.10引用
引用是C++的一个特殊的数据类型描述,用于在程序的不同部分使用两个以上的变量名指向同一地址,使得对其中任一个变量的操作实际上都是对同一地址单元进行的。在这种两个以上变量名的关系上,被声明为引用类型的变量名则是实际变量名的别名。引用运算符为&,声明引用的一般形式为:
数据类型
&引用变量名=变量名;对引用操作,实际上就是对被引用的变量操作。引用不是值,不占存储空间,声明引用时,目标的存储状态不会改变。引用一旦被初始化,就不能再重新赋值。#include<iostream.h>voidmain(){
intnum=50;int&ref=num;
ref+=10;
cout<<"num="<<num<<endl;
cout<<"ref="<<ref<<endl;num+=40;
cout<<"num="<<num<<endl;
cout<<"ref="<<ref<<endl;}
【例2.5】引用举例。
num=60ref=60num=100ref=100关于引用的说明:(1)在一行上声明多个引用型变量(函数)名时,要在每个变量(函数)名前都冠以“&”符号。
(2)引用不是变量,所以引用本身不能被修改,在程序中对引用的存取都是对它所引用的变量的存取。
(3)一个变量被声明为引用时必须进行初始化,除非这个引用是用作函数的参数或返回值,为引用提供的初始值应为变量。引用一旦被初始化,就不能再重新赋值。
(4)由于引用不是变量,所以,不能说明引用的引用,也不能说明数组元素的类型为引用数组,或指向引用的指针。例如:
int&a[5];//错误
int&*p; //错误关于引用的说明:(5)由于指针也是变量,因此可以说明对指针变量的引用。例如:
int*a;int*&p=a;intb;p=&b;
//a指向变量b(6)引用与指针不同。指针的值是某一变量的内存单元地址,而引用则与初始化它的变量具有相同的内存单元地址。指针是个变量,可以把它再赋值成其它的地址,然而,建立引用时必须进行初始化并且决不会再指向其它不同的变量。
(7)要注意区分引用运算符和地址运算符的区别。
intnum=50;int&ref=num;int*p=&ref;关于引用的说明:(8)可以用一个引用初始化另一个引用。例如:
intnum=50;int&ref1=num;
int&ref2=ref1;ref2=100; //num为100
其中ref2也是对num的引用。
(9)函数调用可以作为左值引用表达式是一个左值,因此它可以出现在形、实参数的任何一方。若一个函数返回了引用,那么该函数的调用也可以被赋值。一般说,当返回值不是本函数内定义的局部变量时就可以返回一个引用。在通常情况下,引用返回值只用在需对函数的调用重新赋值的场合,也就是对函数的返回值重新赋值的时候。避免将局部作用域中变量的地址返回,就使函数调用表达式作为左值来使用。【例2.8】【例2.9】
28
在C++中,任何命名的存储区域都称为左值,这个存储区域的内容可以被修改。任何未命名的存储区域,如堆栈中创建的临时变量,称为右值;右值表示一个表达式运算后的值,如果是基本类型,就不能修改;如果是用户自定义类型,就可以被修改,且称为可修改的右值。对于inta(10),&ra=a;语句,下列描述错误的是( )。ra是变量a的引用,即为变量的别名ra的值为10ra的地址值为&a改变ra的值为20,变量a的值仍为10ABCD提交可为此题添加文本、图片、公式等解析,且需将内容全部放在本区域内。正常使用需3.0以上版本上述语句中定义了基本整型变量a,其初始值为10,ra为变量a的引用,即a的别名,变量a的值即为引用ra的值,对ra的值进行修改,实质上是修改了变量a的值,ra的地址值即为变量a的地址值&a,实际上取引用ra的地址值没有任何意义。答案解析答案解析单选题1分2.11const修饰符#definePI3.1415926constdoublePI=3.1415926;
这个常量是有类型的,它有地址,可以用指针指向这个值,但不能修改它。C++建议用const取代#define定义常量。与#define定义的常量有所不同,const定义的常量可以有自己的数据类型,这样C++编译程序可以进行更加严格的类型检查,具有良好的编译时的检测性。
(1)使用const修饰符定义常量时,必须初始化;
(2)函数参数也可以用const说明,用于保证实参在该函数内部不被改动,大多数C++编译器能对具有const参数的函数进行更好的代码优化。例如,通过函数max求出整型数组a[100]中的最大值,函数原型应该是:
intmax(constint*pa);
这样做的目的是确保原数组的数据不被破坏,即在函数中对数组元素的操作只许读,不许写。关于const的说明:const与指针一起使用的组合情况:
(1)指向常量的指针指向常量的指针是一个指向常量的指针变量。
constchar*pc="abcd";
声明指向常量的指针变量pc,指向一个字符串常量。由于使用了const,不允许改变指针所指的常量,因此以下语句是错误的:
pc[3]='x';
但是由于pc是一个指向常量的普通指针变量,不是常指针,因此可以改变pc的值。例如以下语句是允许的:
pc="jkkk";const与指针一起使用的组合情况:
(2)常指针常指针是指针本身,而不是它指向的对象声明为常量。例如:
char*constpc="abcd";
//常指针这个语句的含义为:声明一个名为pc的指针变量,该指针是指向字符型数据的常指针,用“abcd”的地址初始化该常指针。创建一个常指针,就是创建不能移动的固定指针,但是它所指的数据可以改变。例如:
pc[3]='x';
//合法
pc="dfasdfa";
//不合法const与指针一起使用的组合情况:
(3)指向常量的常指针整个指针本身不能改变,它所指向的值也不能改变。要声明一个指向常量的常指针,二者都要声明为const。
constchar*constpc="abcd";
这个语句的含义为:声明一个名为pc的指针变量,它是一个指向字符型常量的常指针,用“abcd”的地址初始化该指针。以下两个语句都是错误的:
pc[3]='x';
//错误,不能改变指针所指的值
pc="dfasdfa";
//错误,不能改变指针本身2.13C++语言中函数的新特性2.13.2
内联(inline)函数2.13.3
带缺省参数的函数2.13.4
函数重载(overload)2.13.5
函数模板(functiontemplate)2.13.2 内联(inline)函数在执行程序过程中如果要进行函数调用,则系统要将程序当前的一些状态信息存到栈中,之后进行虚实结合,同时转到函数的代码处去执行函数体语句,这些参数保存与传递的过程中需要时间和空间的开销,使得程序执行效率降低,特别是在程序频繁地进行函数调用以及函数代码段比较少时,这个问题会变得更为严重。为了解决这个问题,C++引入了内联函数机制。使用内联函数是一种用空间换时间的措施,若内联函数较长,且调用太频繁时,程序将加长很多。因此,通常只有较短的函数才定义为内联函数,对于较长的函数最好作为一般函数处理。2.13.2 内联(inline)函数一般情况下,我们对内联函数做如下的限制:(1)不能有递归(2)不能包含静态数据(3)不能包含循环(4)不能包含switch和goto语句(5)不能包含数组若一个内联函数定义不满足以上限制,则编译系统把它当作普通函数对待。【例2.11】内联函数的使用。
332.13.3 带默认参数的函数如果在函数说明或函数定义中为形参指定一个默认值,则称此函数为带默认参数的函数。当函数调用发生后,在形参表中等号后的各“默认值”将起实参的传递作用。voidfun(inta,intb=1,intc=4,intd=5);如果函数有多个默认参数,则默认参数必须是从右向左定义,并且在一个默认参数的右边不能有未指定默认值的参数。
voidfun(inta=3,intb=6,intc,intd);voidfun(inta=65,intb=3,intc,intd=3);需要特别注意的是如果在函数原型的声明中设置了函数参数的默认值,则不可再在函数定义的头部重复设置,否则编译时将出现错误信息。voidfun(int,int=1,int=4,int=5);
35思考下列关于设置缺省参数值的描述中,错误的是( )。可对函数的部分参数或全部参数设置缺省值在有函数原型时,缺省值应该设置在函数原型中,而不是函数定义时设置函数缺省参数值时,只可用常量,不可用含有变量的表达式设置函数参数默认值应从右向左设置ABCD提交可为此题添加文本、图片、公式等解析,且需将内容全部放在本区域内。正常使用需3.0以上版本函数的缺省参数从最右边开始,中间不能间隔非缺省参数;可以对函数的部分或全部参数设置缺省值;在有函数原型时,缺省值应该设置在函数原型中,而不是函数定义时;缺省值可以使用常量,也可以是变量或含有变量的表达式。单选题1分答案解析2.13.4 函数重载(overload)C++编译系统允许为两个或两个以上的函数取相同的函数名,但是形参的个数或者形参的类型不应相同,编译系统会根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是所谓的函数重载。函数重载无需特别声明,只要所定义的函数与已经定义的同名函数形参形式(类型、个数)不完全相同,C++编译器就认为是函数的重载。【例2.12】重载函数应用举例
36在使用重载函数时要注意:①不可以定义两个具有相同名称、相同参数类型和相同参数个数,只是函数返回值不同的函数。
intfunc(intx);
floatfunc(intx);②如果某个函数参数有缺省值,必须保证其参数缺省后调用形式不与其它函数混淆。
intf(inta,floatb);
voidf(inta,floatb,intc=0);
函数调用语句:f(10,2.0);具有二义性,既可以调用第一个函数,也可以调用第二个函数,编译器不能根据参数的形式确定到底调用哪一个。【例1】下列选择重载函数的不同实现的判断条件中,错误的是(
)。参数类型不同参数个数不同参数顺序不同函数返回值不同ABCD提交可为此题添加文本、图片、公式等解析,且需将内容全部放在本区域内。正常使用需3.0以上版本重载函数是指函数名相同而参数有所不同的函数,参数不同包括参数类型
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 农村道路养护考核制度
- 酒店保洁人员考核制度
- 铁路基本功考核制度
- 商店营业员考核制度
- 学校处室人员考核制度
- 护老院绩效考核制度
- 公园清扫保洁考核制度
- 大学素拓分考核制度
- 公职律师培训考核制度
- 健康教育课考核制度
- 2026年高考英语作文预测模拟题集及答案
- 2026年皖西卫生职业学院高职单招职业适应性测试备考题库含答案解析
- 儿童变应性鼻炎诊断和治疗指南(2025年,修订版)
- 6.0《中国的地理差异》教案-人教版地理八年级下册
- 2025年湖南生物机电职业技术学院单招职业适应性考试模拟测试卷附答案
- (2025年)中式烹调师(初级)模拟题及参考答案
- 2025年中国固态电池行业发展研究报告
- 漫画分镜技巧如何讲述好一个故事
- 四川中烟招聘考试真题2025
- 七年级下英语考试题及答案
- (2021-2025)5年高考1年模拟化学真题分类汇编专题14 化学实验探究综合题(北京专用)(北京专用)
评论
0/150
提交评论