资源预览内容
第1页 / 共73页
第2页 / 共73页
第3页 / 共73页
第4页 / 共73页
第5页 / 共73页
第6页 / 共73页
第7页 / 共73页
第8页 / 共73页
第9页 / 共73页
第10页 / 共73页
亲,该文档总共73页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第9章 多态性与虚函数,9.1 多态性 9.2 虚函数 9.3 纯虚函数和抽象类,9.1 多态性,9.1.1 普通成员函数重载 9.1.2 构造函数重载 9.1.3 派生类指针,返回首页,9.1.1 普通成员函数重载,1函数重载的方法 2函数重载的表示形式 (1)在一个类说明中重载。 (2)基类的成员函数在派生类中重载。 3函数重载的注意事项 4函数重载的二义性,1函数重载的方法,例9-1:给出以下程序的运行结果。 #include int square(int x) return x*x; double square(double y) return y*y; main() ,cout“The square of integer 7 is“square(7)endl; cout“ The square of double 7.5 is“square(7.5)endl; return 0; 此程序的运行结果为: The square of integer 7 is 49 The square of integer 7.5 is 56.25,例9-2:用重载函数实现求圆和矩形的周长。 #include const double PI=3.1415; double length(float r) return 2*PI*r; double length(float x,float y) return 2*(x+y); void main() float a,b,r; coutr;,coutab; cout“矩形周长:“length(a,b)endl; 运行结果为: 输入圆半径:7 圆周长:43.981 输入矩形长和宽:3 4 矩形周长:14,2函数重载的表示形式,例9-3:分析以下程序的执行结果。 #include class Sample int i; double d; public: void setdata(int n) i=n; void setdata(double x) d=x; void disp(), cout“i=“i“,d=“dendl; ; void main() Sample s; s.setdata(7); s.setdata(7.5); s.disp(); 此程序的运行结果为: i=7,d=7.5,有3种编译区分方法: 1)根据参数的特征加以区分。 2)使用“ : ”加以区分。 3)根据类对象加以区分。,3函数重载的注意事项,在C+语言中,编译程序选择相应的重载函数版本时函数返回值类型是不起作用的。不能仅靠函数的返回值来区别重载函数,必须从形式参数上区别开来。例如: void print(int a); void print(int a,int b); int print(float a); 这三个函数是重载函数,因为C+编译程序可以从形式参数上将它们区别开来。但: int f(int a); double f(int a);,4函数重载的二义性,函数重载的二义性(ambiguity)是指C+语言的编译程序无法在多个重载函数中选择正确的函数进行调用。这些二义性错误是致命的,因而编译程序将无法生成目标代码。函数重载的二义性主要源于C+语言的隐式类型转换与默认参数。,例9-4:隐式类型转换造成函数重载二义性示例。 #include float abs(float x) return (x0?x:-x); double abs(double x) return (x0?x:-x); int main() coutabs(1.78)endl; /调用abs(double) /coutabs(-7)endl; /错误,编译程序无法确定调用哪一个abs()函数 在重载函数中使用默认参数也可能造成二义性。,返回本节,9.1.2 构造函数重载,构造函数可以像普通函数一样被重载,而且也可能是C+语言应用函数重载最多的地方,因为设计一个类时总是希望创建对象的同时能以多种方式初始化对象的内部状态,而构造函数只能有一个名字,即该类的名字。当建设一个可复用类库时,重载构造函数可以更好地提高类界面的完整性。,例: class X public: X ( ) ; X( int ) ; X ( int, char ) ; X ( float, char ) ; . ; void f ( ) X a ; / 调用构造函数 X() X b ( 1 ) ; / 调用构造函数 X(int) X c ( 1, c ) ; / 调用构造函数 X(int, char) X d ( 2.3 , d ) ; / 调用构造函数 X(float, char) . ,例9-6:分析下面程序的执行结果。 #include class TDate public: TDate( ); TDate(int d); TDate(int m,int d); TDate(int y,int m,int d); protected: int year; int month; int day; ; TDate:TDate( ) ,year=1999; month=11; day=24; coutyear“/“month“/“dayendl; TDate:TDate(int d) year=1999; month=11; day=d; coutyear“/“month“/“dayendl; TDate:TDate(int m,int d) year=1999; month=m; day=d; coutyear“/“month”/”dayendl; TDate:TDate(int y, int m, int d) year=y; month=m; day=d;,coutyear“/“month“/“dayendl; void main( ) TDate aday; TDate bdate(10); TDate cdate(8,8); TDate ddate(1998,1,1); 输出结果为: 1999/11/24 1999/11/10 1999/8/8 1999/1/1,返回本节,9.1.3 派生类指针,指向基类和派生类的指针是相关的。 例如: A * p ; / 指向类型 A 的对象的指针 A A_obj ; / 类型 A 的对象 B B_obj ; / 类型 B 的对象 p = / p 指向类型 B 的对象,它是 A 的派生类,例9-8:分析以下程序的执行结果。 class A_class char name80; public: void put_name(char *s) strcpy(name,s); void show_name( ) coutname“n“; ; class B_class:public A_class char phone_num80; public: void put_phone(char *num) strcpy (phone_num,num); void show_phone( ) coutphone_num“n“; ;,main ( ) A_class *p; /对象指针 A_class A_obj; /对象 B_class * bp; B_class B_obj; p=,(B_class *)p)-show_phone( ); / 用基类指针访问公有派生类的特定成员,必须进行类型转换 此程序的运行结果为: Zhang San Li Si 0731_12345678 0731_12345678,例9-9:写出下面的程序的执行结果。 #include class Student public: Student(int xx) x=xx; virtual float calcTuition( ); protected: int x; ; float Student:calcTuition() return float(x*x);, class GraduateStudent:public Student public: GraduateStudent(int xx):Student(xx) float calcTuition( ); ; float GraduateStudent:calcTuition( ) return float(x*2); void main( ) Student s(20); GraduateStudent gs(20); couts.calcTuition()endl; /计算学生s的学费 coutgs.calcTuition()endl; /计算研究生gs的学费 输出结果为: 400 400,返回本节,9.2 虚函数,9.2.1 静态联编与动态联编 9.2.2 虚函数的概念 9.2.3 动态联编与虚函数 9.2.4 虚函数的限制 9.2.5 虚函数与重载函数的比较,返回首页,9.2.1 静态联编与动态联编,1静态联编 静态联编是指联编工作出现在编译连接阶段,这种联编又称早期联编,因为这种联编过程是在程序开始运行之前完成的。在编译时所进行的这种联编又称静态绑定。在编译时就解决了程序中的操作调用与执行该操作代码间的关系,确定这种关系又称为绑定,在编译时绑定又称静态束定。下面举一个静态联编的例子。,例9-11:静态联编示例程序。 #include class Point public: Point(double i, double j) x=i; y=j; double Area() const return 0.0; private: double x, y; ; class Rectangle:public Point public: Rectangle(double i, double j, double k, double l);,double Area() const return w*h; private: double w, h; ; Rectangle:Rectangle(double i, double j, double k, double l):Point(i, j) w=k; h=l; void fun(Point 该程序的运行结果为: 0,2动态联编 从对静态联编的上述分析中可以知道,编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序执行时才能确定将要调用的函数,为此要确切知道该调用的函数,要求联编工作要在程序运行时进行,这种在程序运行时进行的联编工作被称为动态联编,或称动态绑定,又叫晚期联编。 动态联编实际上是进行动态识别。,返回本节,9.2.2 虚函数的概念,虚函数是在基类中冠以关键字 virtual 的成员函数。它是动态联编的基础。虚函数是成员函数,而且是非static的成员函数。它提供了一种接口界面,并且可以在一个或多个派生类中被重定义。 说明虚函数的方法如下: virtual () 其中,被关键字virtual说明的函数称为虚函数。,例9-12:分析以下程序的执行结果。 #include class Base public: void who( ) cout“basen“; ; class first_d:public Base public: void who( ) cout“First derivationn“; ;,class s
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号