您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 《VisualC++教程第二版》第3章C++进阶
第3章C++进阶3.1多态和虚函数3.2运算符重载3.3输入输出流库3.4模板3.1多态和虚函数3.1.1虚函数[例Ex_VirtualFunc]虚函数的使用。#includeiostream.hclassCShape{public:virtualfloatarea(){return0.0;}};classCTriangle:publicCShape{public:CTriangle(floath,floatw){H=h;W=w;}floatarea(){return(float)(H*W*0.5);}private:floatH,W;};classCCircle:publicCShape{public:CCircle(floatr){R=r;}floatarea(){return(float)(3.14159265*R*R);}private:floatR;};voidmain(){CShape*s[2];s[0]=newCTriangle(3,4);couts[0]-area()endl;s[1]=newCCircle(5);couts[1]-area()endl;}运行结果为:678.53983.1多态和虚函数说明:(1)虚函数在重新定义时参数的个数和类型必须和基类中的虚函数完全匹配,这一点和函数重载完全不同。(2)虚函数所具备的上述功能,只有通过基类指针才可实现。虚函数在用对象名和成员运算符以正常方式调用时,不能达到其效果。(3)如果不使用new来创建相应的派生类对象,也可用下列方法来实现:voidmain(){CShape*p1,*p2;CTriangletri(3,4);CCirclecir(5);p1=&tri;p2=○coutp1-area()endl;coutp2-area()endl;}(4)虚函数必须是类的一个成员函数,不能是友元函数,不能是静态的成员函数。(5)可把析构函数定义为虚函数,但不能将构造函数定义为虚函数。通常在释放基类及其派生类中的动态申请的存储空间时,也要把析构函数定义为虚函数,以便实现撤消对象时的多态性。3.1多态和虚函数3.1.2纯虚函数和抽象类定义一个基类时,会遇到这样的情况:无法定义基类中虚函数的具体实现,其实现完全依赖于其不同的派生类。例如,一个“形状类”由于没有确定的具体形状,因此其计算面积的函数也就无法实现。这时可将基类中的虚函数声明为纯虚函数。声明纯虚函数的一般格式为:virtual函数类型函数名(形数表)=0;它与一般虚函数不同的是:在纯虚函数的形参表后面多了个“=0”。把函数名赋于0,本质上是将指向函数的指针的初值赋为0。需要说明的是,纯虚函数不能有具体的实现代码。抽象类是指至少包含一个纯虚函数的特殊的类。它本身不能被实例化,也就是说不能声明一个抽象类的对象。必须通过继承得到派生类后,在派生类中定义了纯虚函数的具有实现代码,才能获得一个派生类的对象。与虚函数使用方法相同,也可以声明指向抽象类的指针,虽然该指针不能指向任何抽象类的对象,但可以通过该指针获得对派生类成员函数的调用。事实上,纯虚函数是一个特殊的虚函数。3.2运算符重载3.2.1运算符重载的语法函数类型类名::operator重载的运算符(形参表){…}//函数体运算符重载函数的函数是以特殊的关键字operator开始的,因而编译器很容易与其他的函数名区分开来。重载的运算符必须是合法的运算符。说明:(1)当用成员函数实现双目运算符的重载时,运算符的左操作数一定是对象,右操作数作为调用运算符重载函数的参数,参数可以是对象、对象的引用或是其他类型的参数。(2)不是所有的运算符都可以重载。不允许重载的运算符除三目运算符“?:”外,还有成员操作符“.”、成员指针取值操作符“*”、作用域操作符“::”以及sizeof运算符。(3)只能对已定义了的运算符进行重载,而且当重载一个运算符时,该运算符的操作数个数、优先级和结合性是不能改变的。3.2运算符重载[例Ex_Complex]运算符的简单重载。#includeiostream.hclassCComplex{public:CComplex(doubler=0,doublei=0){realPart=r;imagePart=i;}voidprint(){cout该复数实部=realPart,虚部=imagePartendl;}CComplexoperator+(CComplex&c);//重载运算符+CComplexoperator+(doubler);//重载运算符+private:doublerealPart;//复数的实部doubleimagePart;//复数的虚部};CComplexCComplex::operator+(CComplex&c)//参数是CComplex引用对象{CComplextemp;temp.realPart=realPart+c.realPart;temp.imagePart=imagePart+c.imagePart;returntemp;}3.2运算符重载CComplexCComplex::operator+(doubler)//参数是double类型数据{CComplextemp;temp.realPart=realPart+r;temp.imagePart=imagePart;returntemp;}voidmain(){CComplexc1(12,20),c2(50,70),c;c=c1+c2;c.print();c=c1+20;c.print();}运行结果为:该复数实部=62,虚部=90该复数实部=32,虚部=20对运算符“+”作了两次重载,一个用于实现两个复数的加法,另一个用于实现一个复数与一个实数的加法。当重载一个运算符时,必须定义该运算符要完成的具体操作,而且当运算符重载函数是类的成员函数时,该函数的形参个数要比运算符操作数个数少一个,双目运算符重载的成员函数只有一个参数,单目运算符重载的成员函数没有参数。3.2运算符重载3.2.2赋值运算符的重载对象的成员中有数组或动态的数据类型时,就不能直接相互赋值,否则在程序的编译或执行过程中出现编译或运行错误。例如:classCdemo{public:CDemo(char*s){ps=newchar[strlen(s)+1];strcpy(ps,s);}~CDemo(){if(ps)delete[]ps;}voidprint(){coutpsendl;}private:char*ps;};voidmain(){CDemod1(Key),d2(Mouse);d1=d2;}程序运行到“d1=d2”时发生运行错误。因此,必须重载“=”运算符,它与其他运算符的重载相同。3.2运算符重载[例Ex_Evaluate]赋值运算符的重载。#includeiostream.h#includestring.hclassCDemo{public://同上面的斜体部分代码CDemo&operator=(CDemo&a)//赋值运算符重载{if(ps)delete[]ps;if(a.ps){ps=newchar[strlen(a.ps)+1];strcpy(ps,a.ps);}elseps=0;return*this;}private:char*ps;};voidmain(){CDemod1(Key),d2(Mouse);d1=d2;d1.print();}运行结果为:Mouse赋值运算符不能重载为友元函数,只能是一个非静态成员函数。3.2运算符重载3.2.3提取和插入运算符重载C++允许用户重载“”和“”运算符,以便用户利用标准的输入输出流来输入输出自己定义的数据类型(包括类),实现对象的输入输出。重载这两个运算符时最好将重载声明为类的友元函数,以便访问类中的私有成员。友元重载的一般格式如下:friend函数类型operator重载的运算符(形参)//单目运算符重载{…}//函数体friend函数类型operator重载的运算符(形参1,形数2)//双目运算符重载{…}//函数体对于单目运算符的友元重载函数,只有一个形参,形参类型可以是类的对象,可以是引用,这取决于不同的运算符。对于双目运算符的友元重载函数来说,它有两个形参,这两个形参中必须有一个是类的对象。需要说明的是,=、()、[]和-运算符不能用友元来重载。3.2运算符重载[例Ex_ExtractAndInsert]提取和插入运算符的重载。#includeiostream.hclassCStudent{public:friendostream&operator(ostream&os,CStudent&stu);friendistream&operator(istream&is,CStudent&stu);private:charstrName[10];//姓名charstrID[10];//学号floatfScore[3];//三门成绩};ostream&operator(ostream&os,CStudent&stu){osendl学生信息如下:endl;os姓名:stu.strNameendl;os学号:stu.strIDendl;os成绩:stu.fScore[0],\tstu.fScore[1],\tstu.fScore[2]endl;returnos;}3.2运算符重载istream&operator(istream&is,CStudent&stu){cout请输入学生信息endl;cout姓名:;isstu.strName;cout学号:;isstu.strID;cout三门成绩:;isstu.fScore[0]stu.fScore[1]stu.fScore[2];returnis;}voidmain(){CStudentone;cinone;coutone;}运行结果为:请输入学生信息:姓名:LiMing学号:21010212三门成绩:809075学生信息如下:姓名:LiMing学号:21010212成绩:80,90,753.3输入输出流库3.3.1概述输入输出操作是由“流”来处理的。数据从一个位置到另一个位置的流动抽象为“流”。当流被建立后就可以使用一些特定的操作从流中获取数据或向流中添加数据。从流中获取数据的操作称为“提取”操作,向流中添加数据的操作称为“插入”操作。ios类提供对流状态进行设置的功能,是虚基类,其它类都是从这个派生而来的,streambuf不是ios类的派生类,在类ios中只是有一个指针成员,指向streambuf类的一个对象。streambuf类是用来为ios类及其派生类提供对数据的缓冲支持。itream和ostream类是ios的公有派生类,前者向流中插入数据的有关操作,后者从流中提取数据的有关操作。iostream类是itream和ostream类公有派生的。四个预定义的标准流对象:cin、cout、cerr和clog。当用户在程序中包含了头文件“iostream.h”,编译器调用相应的构造函数,产生这四个标准流对象,用户在程序中就可以直接使用它们了。其中,cin是istream类的对象,用处理标准输入cout是ostream类的对象,用处理标准输出。cerr和clog都是ostream类的对象,用来处理标准出错信息,并将信息显示在屏幕上。在这四个标准流对象中,除了cerr不支持缓冲外,其余三个都带有缓冲区。标准流通常使用提取运算符“”和插入运算符“”来进行输入输出操作的,而且系统还会自动地完成数据类型的转换。3.3输入输出流库3.3.2cout和cin输出流(cout)c
本文标题:《VisualC++教程第二版》第3章C++进阶
链接地址:https://www.777doc.com/doc-2865030 .html