第六章 C++常见问题_第1页
第六章 C++常见问题_第2页
第六章 C++常见问题_第3页
第六章 C++常见问题_第4页
第六章 C++常见问题_第5页
已阅读5页,还剩113页未读 继续免费阅读

下载本文档

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

文档简介

主讲教师:游洪跃个人主页:http:///~youhongyue高级语言程序设计II四川大学计算机学院四川大学计算机学院1教材:《C++面向对象程序设计》李涛主编游洪跃陈良银李琳等编高等教育出版社2006年2月出版2本书内容

第1章绪论第2章C++类和对象第3章继承第4章多态性第5章模板第6章C++常见问题第7章VisualC++编程基础第8章对话框、常用消息、菜单和工具条第9章单文档界面和多文档界面第10章图形设备接口实验(待安排)3提纲动态内存管理技术第六章C++常见问题ARMVectorTableFIQIRQ(Reserved)DataAbortPrefetchAbortSoftwareInterruptUndefinedInstructionReset0x1C0x180x140x100x0C0x080x040x00132Const的使用内联函数的使用使用引用4类型转换5异常处理6命名空间74本章将讨论C++中比较常见的一些问题,这部分问题比较繁琐,但也是C++中比较核心的问题。比如:动态内存的使用、const的使用等。编制程序时必须涉及这些内容。内存不就是存放数据的空间吗?56.1内联函数的使用内联与非内联函数的主要区别就在于编译时的处理方式不同。在执行效率和空间占用上有差异。我不喜欢内联函数行吗?66.1.1内联函数引入的原因调用函数时,要跳到函数的起始地址去执行,执行完函数的代码后,再返回到调用点继续执行。这种跳转操作需要保存现场及返回地址;返回时,又需要恢复现场。函数调用需要一定的时间开销和空间开销,这会影响程序的执行效率。外联开销7对内联函数,编译器会在程序出现内联函数调用的地方用函数体直接进行替换。目标程序将不存在调用问题,也就不会产生跳转的问题,自然就不存在函数调用所需要的时间和空间开销。在编译时用函数代码替换到调用处,如果函数代码长度比较长,超过了跳转语句所占空间的长度,这自然会增加整个程序的代码量,进而增加了空间的开销。实质是用空间换时间。86.1.2内联函数的定义例6_1:smain6_1.cpp

//1、全局函数定义为内联函数inlinedoubleShow1(doubledX) { returndX*dX;}9//2、在类声明体内实现的函数不用inline关键字,自动是内联函数。 doubleShow2(doubledX)const

{ returndX*dX; }10//3、在函数声明处可加可不加inline关键字。

doubleShow3(doubledX)const; //4、但在实现处必须加inline关键字inlinedoubleCPerson::Show3(doubledX)const{ returndX*dX;}11内联函数使用时注意以下几点。1、在内联函数中不允许用循环语句、开关语句和递归调用语句等。2、内联函数的定义必须出现在第一次调用内联函数之前。3、在类内部定义并实现的成员函数自动是内联函数,但在类内定义成员函数时,如果使用了for()、while()、do{}while()、switch()等语句,该成员函数会自动转为非内联函数。4、内联函数中不能够有静态数据。5、内联函数中不能够有数组说明。126.1.3内联和非内联函数的选择使用内联函数时间开销的减少,以空间的消耗为代价,而且执行效率的提高也不是绝对的。在决定使用内联函数时要进行适当的取舍。不是所有的函数都适合采用内联函数。构造函数和析构函数常常就不适合内联,这是因为构造函数和析构函数在编译时,往往会被编译器附加一大堆代码。全部内联可以吗?13看看CStudent类的构造函数:例6_2:构造函数、析构函数往往不适合作内联函数。smain6_2.cpp

构造函数、析构函数最好不要内联。14CStudent()构造函数看起来是空的,但它可能含有相当多的代码(与编译器的设计有关)。CStudent的构造函数,需要构建4000字节的空间,并且还需要按照基类的要求初始化这些空间,因此它包含了一个复杂的创建过程。构造函数和析构函数最好都在类内声明,类外实现。一般来说,实际编程时最好是不要内联任何函数,除非函数确实很小很简单。不要内联任何函数156.2const的使用const意味着分配了一块不可改变的内存。用const定义或说明常类型量时必须初始化。常类型量,也就是常量。const更重要的用途则在于说明函数参数以及函数返回类型。函数参数16const主要有以下几种用法:1、const说明值常量。2、const说明指针。3、const说明函数参数及其返回值。4、const说明类中的常量和成员函数。Const与指针176.2.1const说明值常量1、说明符号常量,表明符号代表的是一个常量,说明格式如下:doubleconstPI=12;constdoublePI=12; const在前、在后定义都可以。182、说明数组常量,说明格式如下:constint

I_ARRAY[]={3,2,1};3、说明对象常量,说明格式如下:constCInline1

oC1,oC2;在一排逗号隔开的变量中,只需要一个const就行了19const与C语言"#define"的差别:#definePI3.14无参宏不是符号常量,它没有数据类型,没有值,在内存中不分配地址。它是在预处理时作宏替换,不作类型检查。而const定义的常量是符号常量,有数据类型,有值,且其值不可改变,在内存中有地址,编译时要作类型检查。206.2.2const与指针指针涉及三个东西:一个是指针变量本身;另一个是指针——指针变量中所存放的值;再一个就是指针所指向的对象。21指针其实就是地址,它代表的是指针变量中存放的地址值;而指针变量是指用来存放指针的一个变量,它用来存放地址;注意:指针变量本身也有地址,有存储单元;指针所指向的对象是指那片空间所“存放的东西”。指针变量本身的地址,与指针变量所指向的对象的存储地址是两个不同的地址。2223const和指针变量的典型组合有以下三种情况:1、指向常量的指针——”constint*p;”2、常指针——”char*constpc="a";”3、指向常量的常指针——“constchar*constpc="a";”太过分了,如此变化多端!!!!24

const

int*p;char*constpc="a";

constchar*constpc="a";画一条垂直线穿过指针声明中的星号(*)位置。如果const出现在线的左边,则指针指向的对象为常量;如果const出现在线的右边,则指针本身为常量;如果const在线的两边都出现,则二者都是常量,是指向常量的常指针。251指向常量的指针指针指向一个不可改变的量。指向常量。在声明时可以不初始化。该指针可以指向这个常量,也可以指向另一个常量。指针变量里的指针值是可以改变的;但某一个具体指针值(即:某个指针)所指向的那个对象则是不可以改变的。对象不可改变。26它也可以指向变量;从指针角度而言,所指向的是一个常量,通过该指针不能修改它所指向的对象;该指针变量可以存放常量地址也可以存放变量地址。对象不可改变。27constchar*pc="ABCD";

pc[3]='a'; //不可以。pc=“EFGH”; //可以//step是一个指向常量的指针数组constchar*step[3]={"left","right","top"};step[2]="skip"; //可以。step[2][1]='i'; //不可以。282常指针

<类型>*const<指针名>[=<初值>;]指针变量里面存放的是个常量,称为常指针,指针变量里面装的是一个固定值,在定义时必须初始化。常指针一旦初始化后,不能够再指向其他内存单元。通过常指针可以修改它所指向的内存单元的内容,也就是修改常指针所指向的对象。29char*constpc="ABCD"; //常指针pc[3]='a'; //可以。pc="EFGH"; //不可以//step是一个常指针数组char*conststep[3]={"left","right","top"};step[2]="skip"; //不可以。step[2][1]='i'; //可以。303指向常量的常指针指针本身及指针所指向的对象都不可改变。二者都要声明为const。在声明时必须初始化。指针本身及其指向的对象均不能改变。constchar*constpc="asdf";

pc[3]='a'; //不可以。pc="ABCD"; //不可以。316.2.3const说明函数参数和返回值是const最重要的应用。在值传递场合不必用const。用const去修饰用指针和引用传递的函数参数,是安全的。const修饰函数的返回值。安全的32voidFunc(constchar*lpszChar);voidFunc(charconst*lpszChar);//以上二者等价。//参数是对象的常引用,返回值也是一个对象的常引用。constCStudent&Func(const

CStudent&oCStudent); 对返回值使用const也有可能提高函数的安全性和效率。336.2.4类中的const在类中,const的使用也比较广。它可以用于修饰类中的成员函数和成员数据。主要应用341常成员函数不可以改变对象数据成员的函数。在一般成员函数后面加上const即可。1、用const关键词修饰一个成员函数,说明该成员函数是“只读”的。2、只有常成员函数可以操作常对象,常对象只能调用常成员函数(const成员函数)。3、一般对象不但可以调用一般成员函数,也可以调用常成员函数。35例6_3:常对象只能够调用常成员函数,不能够调用一般成员函数,而一般对象可以调用所有的成员函数。s6_3\sclass6_3_T.hs6_3\sclass6_3_point.cpp

s6_3\smain6_3.cpp

一般成员函数调用:12一般成员函数调用:23

常成员函数调用:33

36例子表明:仅在const方面有不同的成员函数是可以重载的,编译器能够正确区分这两个函数。而对调用对象来说,一般对象优先调用重载的一般函数,其次才是const函数;常对象(const对象)则只能够调用const函数,不能够调用一般函数。对于一般对象,当调用一般成员函数不成功时,系统自动会转入对常成员函数的调用。372常数据成员若一个数据成员的前面用了关键词const修饰符,则该数据成员为常数据成员。const型的数据必须初始化,且不能修改,它是常数据成员。常数据成员的初始化方式——在定义对象时,通过在构造函数后面加上成员初始化列表来完成的。smain6_4.cpp

38classCPoint //CPoint类{private:

intm_x; //x坐标

constintm_y; //y坐标,常数据成员

staticconstintm_z; //z坐标,静态常数据成员};constint

CPoint::m_z=0; //静态数据成员的初始化方式。//构造函数,m_y采用了初始化表的方式初始化。CPoint::CPoint(intx,inty):m_y(y)

{

m_x=x; //正确。

//m_y=y; //错。}39在CPoint中设置了空间坐标中的m_x、m_y和m_z坐标。分别把它们设置成一般数据成员、常数据成员和静态常数据成员。由于类型不同,它们所采用的初始化方式是很不一样的。在设计构造函数时,最好对一般成员数据也采用初始化表的方式进行初始化。这样效率最高。403常对象常对象就是其值不可改变的对象。它是只可以取值不可以修改的对象。常对象一旦建立并初始化以后,只可以通过常成员函数来访问它。constCPointocCPoint3(3,3);

416.3动态内存管理技术动态对象就是程序在运行过程中在动态内存中建立的对象。这类对象需要用户自己使用new运算符创建,使用delete运算符释放,需要用户自己管理。堆栈静态内存426.3.1内存的几种分配方式计算机内存通常具有三种组织方式:堆、栈和静态内存。1、在静态存储区中分配。静态存储区中的变量空间在编译时分配。静态内存区中的变量在程序的整个运行期间都存在。其生命周期贯穿整个程序的运行周期。例如全局变量,static变量等在这个区间分配。432、在栈上分配。自动变量等局部变量在栈上分配存储空间。函数内的局部变量在栈上分配存储单元。它的生命周期与函数的执行时间相同。当函数执行结束时这些存储单元会被自动释放,其生命周期也就完结了。443、在堆上分配,亦称动态内存分配。动态内存由程序员自己负责管理。运行时用new申请内存。程序员负责在不需要时用delete释放内存。比拉登还麻烦。容易出问题。456.3.2使用new和delete分配和释放动态内存malloc()与free()标准库函数;new/delete运算符(不是库函数)。malloc()/free()功能有限。用户自定义类型在创建对象时要执行构造函数,对象在消亡之前要执行析构函数。而且是自动执行的。所以,C++使用能完成动态内存分配和初始化工作的运算符new,及能完成清理与释放内存工作的运算符delete来管理动态内存。46new运算符new用来动态地分配存储空间。它能够自动计算要分配的存储空间大小并能返回正确的指针类型。若返回值为NULL,则表示动态内存分配不成功。在用new申请动态内存后,一定要判断动态内存是否分配成功。if(p!=NULL)47int*pInt1,*pInt2;pInt1=newint; //new运算返回一整数单元的地址pInt2=newint(200); //new一个int单元,并将其初始化为200。int*pInt3,(*pInt4)[3];

pInt3=newint[10];//new运算返回一整数单元的地址,有10个这样的单元。pInt4=newint[2][3]; //new运算返回每行为3个元素的行地址CPoint*poCPoint;poCPoint=newCPoint(10,10); //new运算返回对象的地址,并在动态内存中创建了一个对象。48使用new运算符创建数组时,不能为该数组指定初值。执行“CPoint

poCPoint=newCPoint(10,10);”语句时,得到了两个东西:一个是对象指针变量,另一个是在动态内存空间中的对象,而指针变量中的值,就是这个动态内存空间中的对象的首地址,也就是动态内存地址。而且这个对象是没有名字的,只有通过指针进行访问。492delete运算符delete释放new所分配的存储空间。<指针名>是存放了要释放的存储空间地址的指针变量名字。释放new所创建数组时,使用“delete[]<指针名>;”的形式。delete只能用来释放用new申请得的动态内存空间,而且一次new只能够对应一次delete。配对使用50deletepInt1;deletepInt2;delete[]pInt3;//释放用new申请的数组空间//释放由new申请的数组空间,对多维空间的释放格式与一维空间相同。delete[]pInt4; deletepoCPoint;//释放一个对象51注意:delete后,指针所指向的内存空间就释放了,但指针变量的值并没有改变。指针还指向原来的内存空间。所以,delete以后,应将指针变量的值设置成NULL,让它不再指向原来的内存空间,以免误操作。例6_5:显示了new和delete的基本使用smain6_5.cpp52

CPoint*poCPoint; //创建对象时,自动调用构造函数。

poCPoint=newCPoint[ARRAY_SIZE];//判断动态内存申请是否成功。

if(poCPoint==NULL) {

cout<<"动态内存分配失败。\n"; exit(0);//内存申请失败,则退出. }53

delete[]poCPoint; //释放对象数组。

//动态内存释放后,让poCPoint指针指向NULL。否则,它依然指向原动态空间。

poCPoint=NULL;

其内容为垃圾54在例6_5中,数组中的5个对象其坐标都是(0,0,0)。这是由于给数组分配空间时,不能进行初始化(声明时不能够带参数)。也就是说:new一个对象数组时是不能够带参数的。缺省的参数则可以,构造函数缺省值为(0,0,0)。55对象数组的对象初始化有两种方法:1、在类中不定义构造函数,而定义一个成员函数专门用来完成初始化。2、在所定义的类中增加不带参数或带缺省参数的构造函数。动态数组初始化56"poCPoint=newCPoint[ARRAY_SIZE];“对应着: "delete[]poCPoint;";

而:"CTemp*poCTemp=newCTemp(5);” 对应着: "deletepoCTemp;"。如果new和delete形式不对应,结果将不可预测。573new和delete的重载new和delete可以在类内重载,也可以在类外重载。类外重载就是全局函数重载,它会覆盖系统预定义的new和delete功能,。类内:new和delete只能重载为成员函数,不能重载为友元函数。而且,无论是否使用关键字static进行修饰,重载了的new和delete均为类的静态成员函数。58void*operatornew(size_tsize){void*p=malloc(size);return(p);}voidoperatordelete(void*p);{free(p);}596.3.3常见的动态内存错误编译器不能自动发现动态内存错误。在程序运行时才能捕捉到。常见的动态内存错误有:1、使用未分配成功的动态内存空间。在使用动态内存之前必须检查指针是否为NULL:函数入口处:assert(p!=NULL)

assert()函数对应的头文件为:assert.h参考《C语言程序设计(C99)》,清华大学出版社申请时用:if(p==NULL)或if(p!=NULL)

进行检查.602、使用未经初始化的动态内存空间。内存的缺省初值可能是一个不确定的值

,所以,任何内存空间的使用都应该立足于自己初始化。尽量不要使用系统缺省的初值。3、超过了内存空间的边界使用数组的操作也很容易越界;越界后就会操作到不正确的内存单元.614、内存泄露。是一种严重的内存错误,极不容易发现。程序长期运行的话,最终会导致内存耗尽。由于new和delete使用不配对new创建的动态空间,没有用delete释放等。5、使用已经释放了的内存空间。用free或delete释放内存以后,指针变量p的值并没有改变,它依然指向原来new的那一片内存空间。释放内存以后,一定要将指针变量的值置成NULL。另外,在传递内存指针时要避免传递栈内存(存储临时变量的内存)。626.3.4指针和数组的对比数组名对应着一块内存,其地址与容量在生命期内保持不变,数组的内容则可以改变;指针变量(尤其void*)则是一个变量,它可以存放任意的地址值,它可以随时指向任意类型的内存块,所以指针远比数组灵活、危险。例6_7说明了指针和数组在使用上的一些差异。使用不慎将引发内存问题。smain6_7.cpp

63Oelloworldhellohello124646.3.5利用指针传递内存的方式利用函数申请动态内存,可以使用指向指针的指针、指针引用以及函数返回指针来传递动态内存。例6_8:利用指向指针的指针、指针引用和函数返回指针传递内存。smain6_8.cpp

hello,world.hello,china.hello,四川大学计算机学院!65例6_9:利用指针传递内存时,注意不要传递栈内存,否则指针会指向垃圾。smain6_9.cpp

栈内存调用的结果为:,静态内存调用的结果为:helloworld在例6_9中:GetString1的return语句返回了指向“栈内存”的指针,它是错误的,因为该内存在函数结束时自动消失;而GetString2虽然返回了正确的结果,但它在设计概念上就已经错误了(因得到的是常量空间)。66以下两者本质上是不同的:charaChar[]="helloworld"; char*aChar="helloworld";动态数组初始化676.3.6delete的作用delete只是把指针所指向的内存给释放掉,它并没有使指针本身消失。delete以后,指针还是指向其原来指向的内存空间,指针变量的值并未改变。指针所指向的内存空间的内容已经释放掉了,其内容变得毫无意义了,是垃圾,指针本身被悬挂了。此时用语句if(p!=NULL)进行防错处理是毫无意义的.68在例6_10中,安排了这种悬挂所带来的问题的示例程序。例6_10:delete对内存干了什么?smain6_10.cpp

lpszChar和lpszChar2指向了同一片动态内存空间,delete以后,内存的内容毫无意义,但是lpszChar和lpszChar2指针变量的值并没有改变,还指向原来的位置。69lpszChar2:屯屯屯屯屯屯屯屯葺葺葺葺葺葺lpszChar:屯屯屯屯屯屯屯屯葺葺葺葺葺葺lpszChar2:hello,China!lpszChar:hello,China!lpszChar2:葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺lpszChar:葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺lpszChar2:helloworld。lpszChar:helloworld。70预防“指针悬挂”(指针所指向的内存空间的内容毫无意义了,是垃圾)和“野指针”(指针的变量是由系统自动生成的一个随机值)从以下几点入手:1、声明指针时记住初始化,如不初始化就一定将其置成NULL.(否则产生野指针)2、指针delete以后,一定记得将其置为NULL。(否则产生指针悬挂)3、当指针指向数组时,谨防指针操作越界.(否则产生指针悬挂)4、避免指针指向一个已经自动消失的局部变量。(否则产生指针悬挂)71voidFunc(void){ char*lpszChar=newchar[100]; }//在退出函数时,动态内存会自动释放吗?72退出Func()的时候,lpszChar会自动消失;而动态内存却依然存在,没有释放,造成内存泄漏。1、指针消亡了,并不表示它所指向的动态内存会自动释放了。2、动态内存释放了,并不表示指向该动态内存的指针会消亡或自动变成NULL指针。736.4使用引用引用(&),就是给一个变量取别名。使用“引用”就是使用“被引用对象”本身它不需要建立临时对象,传递效率较高。6.4.1引用类型intiA,iB;int&riA=iA;//int&riA=iB;//错误,引用是固定的。riA是iA的同义词,它们表示同一个对象。74riA是iA的一个引用;iA是一般变量,它是被引用的对象。定义引用类型变量时必须初始化。引用只能引用一个固定的对象。初始化以后,引用关系就不可改变。对对象或对引用的任何操作都会影响到被引用对象本身。一个引用可看作一个特殊类型的指针。恋爱规则:从一而终751指针引用C中,改变指针本身——采用传指针地址的方式.voidFunc(int

**ppInt);int

iNum=47;int*pInt=&iNum; //&表示取一般变量的地址Func(&pInt); //&表示取指针变量的地址76利用指针引用传递"指针值"。C++中,可以采用引用来完成。函数参数变成指针的引用,用不着取得指针的地址。voidNewMemory3(char*&lpszChar,int

iNum){

lpszChar=newchar[iNum]; if(NULL==lpszChar)

{

cout<<"内存分配失败"<<endl; exit(0); }}77voidTest3(void){ char*lpszStr=NULL;

NewMemory3(lpszStr,100);

strcpy(lpszStr,"hello,world.");

cout<<lpszStr<<endl; deletelpszStr;}传递动态内存(用户定义函数)78

使用引用的限制使用引用时注意两点:1、引用必须初始化。2、引用在初始化中被绑定到某个对象上后,将只能永远绑定这个对象。不可空引用791、引用主要用于函数参数传递,解决大块数据或对象的传递效率和空间效率问题。2、用引用传递函数参数,不产生副本,提高传递效率,通过const的使用,保证了引用传递的安全性。电子汇兑邮局邮寄803、引用与指针的区别:指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。指针使程序可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。引用固定,安全性高;指针可指向任何位置,危险。4、使用引用的时机:重载流操作符<<和>>的参数、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、以及其它部分情况下都推荐使用引用。816.4.2独立引用1、初始化时,赋值表达式的右端是一个变量。例如:int&riNum=iNum;iNum是一个变量。2、初始化时,赋值表达式的右端是一个常量值。例如(VC不允许对常量的引用)constdouble&rd2=1.0;实际上,相当于:constdoublerd2=1.0;82例6_11:引用变量和被引用变量的值同步变化.smain6_11.cpp

500600600500600600836.4.3引用作为函数参数值传递只能实现实参到形参的传值,不能实现形参到实参的反向传值。C++中,需要双向传值时,还可以采用引用。使用引用比使用指针传值更安全,更方便,更直观,更容易理解。例6_12:引用作为参数,产生了双向传值的效果。smain6_12.cpp

84提高传值的效率:

采用引用传值,可以避免复制传值过程,相应地提高了传值的效率。引用就是实参对象本身,不需要复制。如果采用常引用,也不会改变实参,对实参来说也是安全的。例6_13:常引用作参数,在不需要修改实参的时候,保证了所传递参数的安全性。而且传递效率高。smain6_13.cpp

856.4.4引用返回值函数返回引用,返回的是一个存储单元(即变量)。因此,如果一个函数返回引用的话,则函数调用可以出现在赋值号的右边。也可以出现在赋值号的左边。例6_14:引用作为返回值。smain6_14.cpp

86函数返回引用作为左值使用的结果。在函数中未对数组元素作任何修改,但是数组元素值却改变了。这是函数返回引用,并被作为左值操作的结果。

10010200102,4,6,8,10,12,14,16,18,20,2,4,6,8,10,12,100,16,18,20,876.4.5常引用常引用是用const修饰的引用,它常常用做形式参数,用来限制对实参对象的修改。例如://参数是常引用,在函数中不可改变它。voidFunc(constCStudent&oCStudent); //不可通过riNum改变iNum的值。constint&riNum=iNum;

88例6_15:从源复制指定大小的字节数到目的。smain6_15.cpp

程序中,使用了“constvoid*pvFrom”作为形式参数,这保证了实际参数lpszSource的安全性。同时也不会采用复制传值,直接使用lpszSource,传递效率最高。896.5类型转换类型转换就是将一种类型转换为另一种类型:标准类型之间可以相互转换。类类型之间,标准类型和类类型之间也可以相互转换。对于标准类型来说,C++提供了隐式类型转换和显示类型转换两种机制。而自定义类类型到基本类型的转换则可由自己定义的构造函数和类型转换函数来实现。906.5.1构造函数和类型转换函数利用构造函数只能完成基本类型到类类型的转换。从类类型到基本类型的转换需要定义类型转换函数。1基本类型转化为类类型用构造函数进行类型转换有一个前提,就是类中有一个只带一个参数的构造函数。例6_16:实现由实型数,字符串到CDouble类型的转换。smain6_16.cpp91构造函数(1)完成从double型到CDouble类类型的转换;构造函数(2)完成从char*到CDouble类类型的转换,虽然它有2个参数,但第2个参数缺省,所以它也可以只带一个参数转换。变脸92

类类型转化为基本类型完成类类型到基本类型的转换,可采用类类型转换函数来实现。类类型转换函数专门用来将类类型转换为基本数据类型。

operator<基本类型名>(){ //…… return<基本类型值>;}无返回类型93没有返回类型,<类型名>就代表了它的返回类型;没有任何参数。在调用过程中要带一个对象实参。类类型转换函数没有返回类型说明,但函数体必须有return语句,用于返回<基本类型值>。例6_17的"operatorint();"定义了一个类类型转换为基本类型的例子。smain6_17.cpp94CInteger::operatorint(){ returnm_iNum;}定义类类型转换函数时,应注意下列几点:1、转换函数是类的非静态成员函数。2、转换函数定义时,不进行返回值的类型说明,也没有形参。956.5.2一个类型转换实例例6_18:直角坐标到极(矢量)坐标的相互转换。smain6_18.cpp

96X坐标为:2;Y坐标为:2X坐标为:0;Y坐标为:0极径=4;极角=0.523333弧度。极径=0;极角=0弧度。X坐标为:2;Y坐标为:2X坐标为:3.46463;Y坐标为:1.99908极径=4;极角=0.523333弧度。极径=2.82843;极角=0.785398弧度。976.6异常处理出错处理即异常处理是提高程序健壮性的重要手段。异常主要指程序运行时异常。异常处理机制就是用于管理这种异常的一种方法。异常处理的基本结构throw、try和catch语句的一般语法如下:98throw<表达式>;try

{//try语句块}catch(类型1参数1){//针对类型1的异常处理}catch(类型2参数2){//针对类型2的异常处理}//…catch(类型n参数n){//针对类型n的异常处理}1个参数99在设计catch程序时,catch出现的顺序很重要。在一个try块中引发异常时,异常处理程序按照它在catch中出现的顺序进行检查。catch的排列顺序应从特殊到一般的排列顺序(指异常对象从特殊到一般排列)。即应该将派生的异常捕获放在前面,而将基类异常对象的捕获放在处理程序后面。宪法和经济合同法1006.6.1C语言的出错处理C语言的出错处理方法,无法正确地清除对象。C++语言异常处理将异常的检测与处理分开。C++异常处理机制采用结构化方法,就是:throw、try、catch结构。

1、throw:用来创建用户自定义类型的异常错误,用于抛出异常。2、try:标识程序中异常语句块,用于引发异常。3、catch:标识异常错误处理模块,用于捕获、处理异常。1016.6.2抛出异常throw<表达式>;

使用一般方式if(条件)

throw<表达式>异常规格申明(下个页面还将详细介绍)比如:voidExceptionFunction(argument)throw(ExceptionClass1,ExceptionClass2)表示函数ExceptionFunction中可抛出ExceptionClass1或ExceptionClass2类型的异常.如果某段程序发现了自己不能处理的异常,就可以使用throw表达式抛出这个异常,将它抛给调用者。102异常

温馨提示

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

评论

0/150

提交评论