第九章多态性 ●●●●● ●●●● 多态性( polymorphism)也是面向对象程序设计的标志° 性特征。前面我们讨论过面向对象的两个重要特性封装性和 继承性,这三大特性是相互关联的,封装性是基础,继承性是 关键,而多态性是补充 简单地说,在C十语言中,同一程序的某个运算符或者某 个函数名在不同情况下具有不同的实现的现象,叫做多态性。 其实在C语言中,我们已经接触过多态性的应用,对于 不同类型的数据,运算符“”具有不同的运算含义,如果两个 操作数都是整数,那么“”进行整数相除,结果也是整数,而 其中一个操作数是实数类型的,那么“”进行的是数学上普通 的除法,因此,面对不同的处理对象,“”运算符有不同意义 C++支持两种形式的多态性,一种是编译时的多态性,也 称为静态联编,是通过重载来实现的,第二种是运行时的多态 性,也称为动态联编,是通过继承和虚函数来实现的
第九章 多态性 多态性(polymorphism)也是面向对象程序设计的标志 性特征。前面我们讨论过面向对象的两个重要特性—封装性和 继承性,这三大特性是相互关联的,封装性是基础,继承性是 关键,而多态性是补充。 简单地说,在C++语言中,同一程序的某个运算符或者某 个函数名在不同情况下具有不同的实现的现象,叫做多态性。 其实在C语言中,我们已经接触过多态性的应用,对于 不同类型的数据,运算符“\”具有不同的运算含义,如果两个 操作数都是整数,那么“\”进行整数相除,结果也是整数,而 其中一个操作数是实数类型的,那么“\”进行的是数学上普通 的除法,因此,面对不同的处理对象,“\”运算符有不同意义。 C++支持两种形式的多态性,一种是编译时的多态性,也 称为静态联编,是通过重载来实现的,第二种是运行时的多态 性,也称为动态联编,是通过继承和虚函数来实现的
第九章多志性 ●●●●● 编译时的多态性是指程序在编译前就可以确定的多态性,他是通过 ●●● 重载机制来实现,重载包括函数重载和运算符重载。函数重载是允许在同。 程序中一个函数名可以对应多个函数体的实现,形成函数名的多态性 在使用中根据函数的参数具体确定调用哪个函数,而运算符重载允许根据 实际需要重新定义C+语言已有运算符的功能。这种多态性体现出“一个 接口,多个方法”的机制。 运行多态性是指必须在运行中才可以确定的多态性,运行多态性是通 过继承和虚函数来实现的。要产生运行时的多态性,首先要设计一个类层 次,然后在某些类中使用虚函数 编译时的多态性→通过函数的重载和运算 符的重载来实现的。 在C++ 中有两 运行时的多态性是指在程序执行 种多态 前,无法根据函数名和参数来确 性 定该调用哪一个函数,必须在程 运行时的一情况来动态地确仑居执行的具体 序执行过程中,根 多态性
第九章 多态性 编译时的多态性是指程序在编译前就可以确定的多态性,他是通过 重载机制来实现,重载包括函数重载和运算符重载。函数重载是允许在同 一程序中一个函数名可以对应多个函数体的实现,形成函数名的多态性, 在使用中根据函数的参数具体确定调用哪个函数,而运算符重载允许根据 实际需要重新定义C++语言已有运算符的功能。这种多态性体现出“一个 接口,多个方法”的机制。 运行多态性是指必须在运行中才可以确定的多态性,运行多态性是通 过继承和虚函数来实现的。要产生运行时的多态性,首先要设计一个类层 次,然后在某些类中使用虚函数。 在C++ 中有两 种多态 性 编译时的多态性 运行时的 多态性 运行时的多态性是指在程序执行 前,无法根据函数名和参数来确 定该调用哪一个函数,必须在程 序执行过程中,根据执行的具体 情况来动态地确定。 通过函数的重载和运算 符的重载来实现的
第九章多态性 ●●●●● ●●●● ●●0 ●●● ●●●● 91函数重载 92运算符重载 93虚函数 94纯虚函数和抽象类
第九章 多态性 9.1 函数重载 9.4 纯虚函数和抽象类 9.3 虚函数 9.2 运算符重载
91画数重载 ●●●●● ●●●● 在C++语言中,只有在声明函数原型时形式参数的多 ●●●● 或者对应位置的数据类型不同,两个或更多的功能相似的函数 就可以共用一个函数名。这种在同一作用域中允许多个函数使 用同一函数名的措施被称为重载( overloading)。函数重载 是C++程序获得多态性的途径之一。 函数重载的方法: 函数重载要求编译器能够唯一地确定调用一个函数时应执 行哪个函数代码,既采用哪个函数实现。确定函数实现时,要 求从函数参数的个数和类型上来区分。这就是说,进行函数重 载时,要求同名函数在参数个数上不同,或者参数数据类型不 同。否则,将无法实现函数重载 <心画
9.1 函数重载 在C++语言中,只有在声明函数原型时形式参数的个数 或者对应位置的数据类型不同,两个或更多的功能相似的函数 就可以共用一个函数名。这种在同一作用域中允许多个函数使 用同一函数名的措施被称为重载(overloading)。函数重载 是C++程序获得多态性的途径之一。 函数重载的方法: 函数重载要求编译器能够唯一地确定调用一个函数时应执 行哪个函数代码,既采用哪个函数实现。确定函数实现时,要 求从函数参数的个数和类型上来区分。这就是说,进行函数重 载时,要求同名函数在参数个数上不同,或者参数数据类型不 同。否则,将无法实现函数重载
91画数重载 ●●●●● ●●●● include //9-1-1. cpp ●●0 ●●● ●●●● int square (int x) cut<<"(int类型函数被调用)”; return x*x double square double y cout<<"( double类型函数被调用)”; return y*y maino cout<<"整数7的平方是:”<< square(7)<<end cout<<"实数75的平方是:”<< square(75) <<enda return OF <心画
9.1 函数重载 #include // 9-1-1.cpp int square(int x) { cout << “(int 类型函数被调用)”; return x*x; } double square(double y) { cout << “(double 类型函数被调用)”; return y*y; } main() { cout<<”整数 7 的平方是:” << square(7) <<endl; cout<<” 实 数 7.5 的平方是: ” << square(7.5) <<endl; return 0; }
9.1画齦重载 ●●●●● ●●●● ●●0 例:用重载函数实现求圆和矩形的周长。 ●●● ●●●● #include void maino//9-1-2. cpp const double pi-31415. float a, b,r, double length(float r) cout> r cout<“圆周长:”<< length(r) loubie lens ngth(float x, float yendl i return 2*(x+y) cou<<“输入矩形长和宽:”; cIn cout<<“矩形周长:” < length(a, b)<<endl <心画
9.1 函数重载 #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() // 9-1-2.cpp { float a,b,r; cout > r; cout > a >> b; cout << “矩形周长:” << length(a, b) <<endl; }
91画数重载 ●●●●● 函数重载的表示形式 ●●●● ●●0 普通成员函数重载可表达为两种形式: ●●● ●●●● 1.在一个类说明中重载 例如: Show( int, char )i Show( char float)i 2.基类的成员函数在派生类重载。有3种编译区分方法 (1)根据参数的特征加以区分 例如: show〔int,char)与 Show( char * float) 不是同一函数,编译能够区分 (2)使用“:"加以区分 例如:A:Show()有别于B:Show() (3)根据类对象加以区分 例如: Aobj Show()调用A:Show( Bobj show()调用B:Show()
9.1 函数重载 函数重载的表示形式 普通成员函数重载可表达为两种形式: 1. 在一个类说明中重载 例如: Show ( int , char ) ; Show ( char * , float ) ; 2. 基类的成员函数在派生类重载。有3种编译区分方法 (1)根据参数的特征加以区分 例如: Show ( int , char ) 与 Show ( char * , float ) 不是同一函数,编译能够区分 (2)使用“ :: ”加以区分 例如: A :: Show ( ) 有别于 B :: Show ( ) (3)根据类对象加以区分 例如: Aobj.Show ( ) 调用 A :: Show ( ) Bobj.Show ( ) 调用 B :: Show ( )
9.1画数重载 ●●●●● 函数重载的注意事项 ●●●● ●●0 在C++语言中,编译程序选择相应的重载函数版本时 函数返回值类型是不起作用的。不能仅靠函数的返回值来 区别重载函数,必须从形式参数上区别开来。例如: void print(int ai void print(int a, int b)i int print(float a Di 这三个函数是重载函数,因为C++编译程序可以从形 式参数上将它们区别开来。 但: int f(int a) double f(int a) 这两个函数就不是重载函数,编译程序认为这是对一个 函数的重复说明,因为两个函数的形式参数个数与相应位 置的类型完全相同。 <心画
9.1 函数重载 函数重载的注意事项 在C++语言中,编译程序选择相应的重载函数版本时 函数返回值类型是不起作用的。不能仅靠函数的返回值来 区别重载函数,必须从形式参数上区别开来。例如: void print(int a); void print(int a,int b); int print(float a[]); 这三个函数是重载函数,因为C++编译程序可以从形 式参数上将它们区别开来。 但: int f(int a); double f(int a); 这两个函数就不是重载函数,编译程序认为这是对一个 函数的重复说明,因为两个函数的形式参数个数与相应位 置的类型完全相同
91画数重载 ●●●●● 同样道理,不同参数传递方式也无法区别重载函数,延 void func(int value)i ●●●● void func(int &value); 也不能作为重载函数 在程序中不可滥用函数重载,不适当的重载会降低程序 的可读性。C++语言并没有提供任何约束限制重载函数之 间必须有关联,程序员可能用相同的名字定义两个互不相关 的函数。实际上函数重载暗示了一种关联,不应该重载那些 本质上有区别的函数,只有当函数实现的语义非常相近时才 应使用函数重载 函数重载的二义性 函数重载的二义性( ambiguity)是指C++语言的编 译程序无法在多个重载函数中选择正确的函数进行调用。函 数重载的二义性主要源于C++语言的隐式类型转换与默认 参数
9.1 函数重载 同样道理,不同参数传递方式也无法区别重载函数,如: void func(int value); void func(int &value); 也不能作为重载函数。 在程序中不可滥用函数重载,不适当的重载会降低程序 的可读性。C++语言并没有提供任何约束限制重载函数之 间必须有关联,程序员可能用相同的名字定义两个互不相关 的函数。实际上函数重载暗示了一种关联,不应该重载那些 本质上有区别的函数,只有当函数实现的语义非常相近时才 应使用函数重载。 函数重载的二义性 函数重载的二义性(ambiguity)是指C++语言的编 译程序无法在多个重载函数中选择正确的函数进行调用。函 数重载的二义性主要源于C++语言的隐式类型转换与默认 参数
91画数重载 ●●●●● 在函数调用时,编译程序将按以下规则选择重载函数。 如果函数调用的实际参数类型与一个重载函数形式参数类型 完全匹配,则选择调用该重载函数;如果找不到与实陈参数 类型完全匹配的函数原型,但如果将一个类型转换为更高级 类型后能找到完全匹配的函数原型,编译程序将选择调用该 重载函数。所谓更高级类型是指能处理的值域较大,如int转 换为 unsigned int, unsigned int转换为long,long转换为 unsigned float等。 例如: int func(double d count<<funcA) 虽未声明函数原型 int func(char),但函数调用func (“A)并不会产生任何问题,因为编译程序自动将字符‘A 转换为 double类型,然后调用函数 rint fund( double)。 隐式类型转换是由C+十编译程序自动完成的,这种类型 转换是引起函数重载二义性的主要原因。 <心画
9.1 函数重载 在函数调用时,编译程序将按以下规则选择重载函数: 如果函数调用的实际参数类型与一个重载函数形式参数类型 完全匹配,则选择调用该重载函数;如果找不到与实际参数 类型完全匹配的函数原型,但如果将一个类型转换为更高级 类型后能找到完全匹配的函数原型,编译程序将选择调用该 重载函数。所谓更高级类型是指能处理的值域较大,如int转 换为unsigned int,unsigned int转换为long,long转换为 unsigned float等。 例如:int func(double d); … count<<func(‘A’); 虽未声明函数原型int func(char),但函数调用func (‘A’)并不会产生任何问题,因为编译程序自动将字符‘A’ 转换为double类型,然后调用函数int func(double)。 隐式类型转换是由C++编译程序自动完成的,这种类型 转换是引起函数重载二义性的主要原因