1、010多态多态一、什么是多态 不同对象接收到相同的消息时,产生不同的结果。二、多态的分类 有通用多态(参数多态,包含多态)和专用多态(重载多态,强制多态)。 参数多态:模板;包含多态:虚函数;重载多态:函数及运算符重载;强制多态:强制类型转换。三、多态的实现编译时的多态(重载实现。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。)和运行时的多态(虚函数实现。直到系统运行时,才根据实际情况决定实现何种操作。)。编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。四、虚函数多态1无虚函数利用指针时产生的歧义问题#includ
2、e “iostream.h”class base public: void show() cout”基类的内容n”;class sub:public base public: void show() coutshow(); p=&b; p-show();/(sub *)p)-show();可显示子类内容 通过指针引起的普通函数调用,仅与指针(或引用)的类型有关,而与此时指针正指向的对象无关。一个指向基类的指针可用来指向从基类公有派生的任何的对象,它是C+实现运行时多态的关键途径。2为了使用对象指针表达动态性质,引入虚函数虚函数是为了实现多态,也就是要用基类指针调用派生类的方法,虚函数常常出现在
3、一些抽象接口类定义里。定义格式: virtual 函数类型 函数名(形参表) 函数体虚函数在基类中定义,在派生类(public类型)中重载,在派生类中重写时可以加virtual也可以不加。虚函数被多层次公有继承也仍为虚函数,也可以在派生类中重定义。#include “iostream.h”class base public: virtual void show() cout”基类的内容n”;class sub:public base public: void show() coutshow(); pc=&b; pc-show();/随指针移动,动态实现了单界面,多实现版本3.虚析构函数 一个类
4、拥有虚析构函数表明它是一个基类。用虚析构函数是为了解决当用基类的指针指向派生类时,如果删除此指针,要调用派生类的析构函数(虚函数的作用)。如:base* p=new sub();delete p;/调用派生类的析构函数有时,一个类想跟踪它有多少个对象存在。一个简单的方法是创建一个静态类成员来统计对象的个数。这个成员被初始化为0,在构造函数里加1,析构函数里减1。比如,设想在一个军事应用程序里,有一个表示敌人目标的类:class enemytarget public: enemytarget() +numtargets; enemytarget() -numtargets; static int
5、 numoftargets() return numtargets; private: static int numtargets; ;敌人的坦克是一种特殊的敌人目标,所以会很自然地想到将它抽象为一个以公有继承方式从enemytarget派生出来的类:class enemytank: public enemytarget public: enemytank() +numtanks; enemytank() -numtanks; static int numoftanks() return numtanks; private: static int numtanks;但这段代码当通过基类的指针去
6、删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。int main() enemytarget *p=new enemytank(); cout”现在敌军坦克数量是:”enemytank:numoftanks()endl; delete p; p=NULL;cout”现在敌军坦克数量是:”enemytank:numoftanks()endl; return 0;但一个类中如果不包含虚函数,则说明该类一般不做基类,则无必要定义虚析构函数。因为虚函数会产生一个指向虚函数表函数指针,使程序点用额外的空间。五、纯虚函数和抽象类1纯虚函数是一个在基类中说明的虚函数,它在基类中没有定义,但要
7、在子类中进行定义。格式: virtual 函数类型 函数名(参数表)=0;例:#include “iostream.h”class circle public: void setr(int x) r=x; virtual void show()=0; protected: int r;class area:public circle public: void show() cout”面积是:”3.14*r*rendl;class meter:public circle public: void show() cout”周长是:”2*3.14*rshow(); obj2.setr(20); p=
8、&obj2; p-show();2抽象类 至少含有一个纯虚函数的类就叫抽象类。(1) 抽象类只能做为其它类的基类,不能实例化对象。(2) 不能从具体类派生抽象类。(3) 派生类中没有重定义纯虚函数,则它仍为抽象类。六、重载多态(运算符重载)1 运算符重载目的:为解决非C+语言预定义的新数据类型的运算,它是对已有的运算符赋予了多重含义,同一个运算符作用于不同类型的数据导致不同类型的行为。比如复数的运算。包括单目运算符和双目运算符重载。2 C+可以重载的运算符+-*/%=!=&|!&|=+=-=*=/=%=&=|=+-*,-()newdelete不可以重载的运算符:.*:?:sizeof3 运算符
9、重载原则:重载之后运算符的优先级和结合性不会发生改变;运算符重载是针对新类型数据的实际需要,对原有的运算符进行适当的改造,所以一般来讲,重载的功能应当与原有功能相类似,不能改变原运算符的操作对象个数,同时至少要有一个操作对象是自定义类型。4 运算符重载必须写一个运算符函数,函数格式(也可以是友元函数,但new和delete除外):类名 operator运算符() /相关功能语句;5 单目运算符的重载单目运算符中+和重载格式为:类名 operator 运算符();/前置重载类名 operator 运算符(int);/后置重载例:取负运算“-”的重载:对某一复数取负。#include “iostr
10、eam.h”class complex public: complex operator-(); void input(float r,float v); void disp(); private: float rpart; float vpart;complex complex:operator-() rpart=-rpart; vpart=-vpart; return *this;void complex:input(float r,float v) rpart=r; vpart=v;void complex:disp() cout=0) coutrpart”+”vpart”i”endl;
11、else coutrpartvpart”i”endl;main() complex A; A.input(10,25); A=-A;/隐式调用 / A.operator-(); 显式调用 A.disp();例:+运算前置重载#include “iostream.h”class exam public: exam operator+(); void input(int ,int); void output(); private: int a; int b;exam exam:operator+() +a; +b; return *this;void exam:input(int x,int y)
12、 a=x;b=y;void exam:output() cout”a:”a” b:”bendl;main() exam ex,exx; ex.input(1,2); +ex; ex.output(); ex.operator+(); ex.output(); exx=+ex; exx.output(); 例:-后置重载#include “iostream.h”class number public: number operator-(int); void input(int ,int); void disp(); private: int a,b;number number:operator-
13、(int) number tmp; tmp=*this; a-; b-; return tmp;void number:input(int x,int y) a=x;b=y;void number:disp() cout”a:”a” b:”bendl;main() number n1,n2; n1.input(10,20); n1-; n1.disp(); n1.operator-(0); n1.disp(); n2=n1-; n2.disp(); n1.disp();6 双目运算符的重载格式:类名 operator运算符(形参表);例:两个字符串的连接运算#include iostream#
14、include string.husing namespace std;class strings private: char name256; public: strings operator+(strings &a); strings(char *b) strcpy(name,b); strings() strings() void out() coutname=0) couti+j”i”endl; else coutij”i”endl; main() complex a1,a2,a3; a1.input(10,20); a2.input(5,-5); a3=a1+a2; a3.outpu
15、t(); 例:重载new和delete运算符。例1:#include iostream.h#include stddef.hclass memmanager public: void *operator new(size_t size); void *operator new(size_t size,char tag); void operator delete(void *p); ;void *memmanager:operator new(size_t size) coutnew1 operatorendl; char *s=new charsize; /coutsizeof(s)endl
16、; /*s=a; return s;void *memmanager:operator new(size_t size,char tag) coutnew2 operatorendl; char *s=new charsize; *s=tag; return s;void memmanager:operator delete(void *p) coutdelete operatorendl; delete (char *)p; /char *s=(char*)p;/ deletes;void main() memmanager *m=new memmanager(); delete m; me
17、mmanager *n=new(B) memmanager; delete n;例2:#include iostream.h#include malloc.hclass rect private: int length,width; public: rect(int l,int w) length=l;width=w; void disp() cout矩形的面积是:length*widthendl; void* operator new(size_t size); void operator delete(void *p);void* rect:operator new(size_t size
18、) cout重载new运算符分配内存n; return malloc(size);void rect:operator delete(void *p) coutdisp(); delete p;七、类型转换1隐式转换2显式转换格式:(类型名)表达式八、模板1函数模板 格式: template 返回类型 函数名(模板形参) 函数体;例:将求两数中大的数定义为函数模板 template /class 可写为typename T max(T x,T y) return (xy)?x:y;模板的使用:(1)一个类型参数的函数模板#include “iostream.h”template T max(T
19、 x,T y) return (xy)?x:y;main() int i1=3,i2=45; float f1=12.5,f2=34.6; double d1=7,d2=90; char c1=a,c2=Y; coutmax(i1,f1)endl; coutmax(f1,f2)endl; coutmax(d1,d2)endl; coutmax(c1,c2)endl; (2)有两个参数的函数模板#include “iostream.h”template / templatevoid output(type1 x,type2 y) coutx” ”yendl;main() int i1=3,i2=
20、45; float f1=12.5,f2=34.6; double d1=7,d2=90; char c1=a,c2=Y; output (i1,i2); output (f1,f2); output (d1,d2); output (c1,c2); output (i1,c2); output (i2,f1); output (f2,d2);2类模板 格式: template class 类名 /; 类模板的使用:类名 对象名;#include iostream.h/#include “string”template / template class ABC public: void inp
21、ut(type a); / x=a; void output() coutxendl; private: type x;/template /void ABC:input(type a)/ x=a;/ template /void ABC:output()/ coutxendl;main() ABC obj1; obj1.input(23); obj1.output(); ABC obj2; obj2.input(45.5); obj2.output(); ABC obj3; obj3.input(E);obj3.output(); /ABC obj4; /obj4.input(“这是一个模板
22、的示例子”); /obj4.output(); 作业:九、练习1.关于虚函数,正确的描述是:A.构造函数不能是虚函数 ( )B.析构函数不能是虚函数C.虚函数可以是友元函数D.虚函数可以是静态成员函数2.要实现动态联编,派生类中的虚函数: ( )A.返回的类型可以与虚函数的原形不同B.参数个数可以与虚函数的原形不同C. .参数类型可以与虚函数的原形不同D.以上都不对3.如果在基类中将show声明为不带返回值的纯虚函数,正确的写法是: ( )A.virtual show()=0;B. virtual void show();C. virtual void show()=0;D. void sho
23、w()=0 virtual;4.下面的程序段中虚函数被重新定义的方法正确吗?为什么?class basepublic: virtual int f(int a)=0; / /.;class derived:public base public: int f(int a, int b) return a*b; / /.;5.分析以下程序的运行结果:# include class Stockpublic:void print()cout” Stock class.n”;class Derl_Stock: public Stockpublic:void print()cout” Der1_Stock class.n”;class Der2_Stock: public Stockpublic:void print()coutprint();ptr=&d1;ptr-print();ptr=&d2;ptr-print();6.修改上一题的程序,使运行结果为:Stock class. Der2_Stock class.Der2_Stock
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1