第五章多态性
1 第五章 多态性
5.1编译时的多态性与运行时的多态性 多态性是指用同一个名字定义不同的函数,这些函数执行不同但 又类似的操作。 联编的概念: 个源程序经过编译、连接、成为可执行文件的过程是把可执行 代码联编(或称装配)在一起的过程 静态联编(前期联编) 静态联编要求在程序编译时就知道调用哪个函数,就决定如何 实现某一动作。 动态联编(后期联编、滞后联编) 直要到程序运行时才能确定调用哪个函数。系统在运行时才动 态完成的联编。 静态联编支持的多态性称为编译时多态性,也称静态多态性。在 C+中,编译时多态性是通过函数重载和运算符重载实现的。 动态联编支持的多态性称为运行时多态性,也称动态多态性。在 C+中,运行 时多态性是通过继承和虚函数来实现的
2 5.1 编译时的多态性与运行时的多态性 多态性是指用同一个名字定义不同的函数,这些函数执行不同但 又类似的操作。 联编的概念: 一个源程序经过编译、连接、成为可执行文件的过程是把可执行 代码联编(或称装配)在一起的过程。 静态联编(前期联编) 静态联编要求在程序编译时就知道调用哪个函数,就决定如何 实现某一动作。 动态联编(后期联编、滞后联编) 一直要到程序运行时才能确定调用哪个函数。系统在运行时才动 态完成的联编。 静态联编支持的多态性称为编译时多态性,也称静态多态性。在 C++中,编译时多态性是通过函数重载和运算符重载实现的。 动态联编支持的多态性称为运行时多态性,也称动态多态性。在 C++中,运行 时多态性是通过继承和虚函数来实现的
5.2函数重载 编译时多杰性可以通过函数重载来实现。函数重载的意义在于它能 Void main( point p(20, 20) circle c(8,8,30); cout<< parea()<<endl;∥执行基类 point E中的area()的函数 cout<< c area0<<endl;∥执行派生类 circle中的area()函数 cout< C point:area(<<end;/.行基类 point中的area()的函数 程序运行结果为: 0 2827439941 class circle: public pointt int radius, public circle(int x, int y, int rad: point(*,yradius=rad float area( return3,1416 radius* radius;派生类中的area函数
3 5.2 函数重载 编译时多态性可以通过函数重载来实现。函数重载的意义在于它能 用同一个名字访问一组相关的函数,也就是说,能使用户为某一 类操作取一个通用的名字,而由编译程序来选择具体由哪个函数 来执行,因而有助于解决程序的复杂性问题。普通成员函数和构 造函数都可以重载 例5.1 基类和派生类中函数重载的例子 #include class point{ int x,y; public: point(int a,int b){x=a;y=b;} float area(){return 0.0;} //基类中的area函数 }; class circle:public point{ int radius; public: circle(int x,int y,int rad):point(x,y){radius=rad;} float area(){return 3,1416*radius*radius;}//派生类中的area函数 }; Void main() { point p(20,20); circle c(8,8,30); cout<<p.area()<<endl; //执行基类point中的area()的函数 cout<<c.area()<<endl; //执行派生类circle中的area()函数 cout<<c.point::area()<<endl;//执行基类point中的area()的函数 } 程序运行结果为: 0 2827.439941 0
说明 在基类和派生类中的函数重载有两种情况: 参数有所差别的重载,这种重载函数的定义和调用方法在前面章 节已进行了介绍;在编译时根据参数不同来区分函数重载。 2函数所带的参数完全相同,只是它们属于不同的类。这时要人工 干预,以下两种方法可以使编译时区别这类函数: (1)使用对象名加以区分。例如: parea()和 cerea()分别 调用类pon的area()函数和类crce的area()函数 (2)使用类名加以区分。例如: point:area()和 circle:area( 分别调用类 point和类crce的area()函数
4 说明: 在基类和派生类中的函数重载有两种情况: 1.参数有所差别的重载,这种重载函数的定义和调用方法在前面章 节已进行了介绍;在编译时根据参数不同来区分函数重载。 2.函数所带的参数完全相同,只是它们属于不同的类。这时要人工 干预,以下两种方法可以使编译时区别这类函数: (1)使用对象名加以区分。例如:p.area()和c.erea()分别 调用类point的area()函数和类circle的area()函数。 (2)使用类名加以区分。例如:point::area()和circle::area() 分别调用类point和类circle的area()函数
5.3运算符重载 在C++中,除了可以对函数重载外,还可以对大多数运算 符实施重载。 运算符重载通过创建运算符函数 operator()来实现。 运算符函数定义了重载的运算符将要进行的新的操作, 这种操作通常作用在一个类上。 函数 operator()可以不是类的成员函数是类的成 员函数类的友元函数
5 5.3 运算符重载 在C++中,除了可以对函数重载外,还可以对大多数运算 符实施重载。 运算符重载通过创建运算符函数operator()来实现。 运算符函数定义了重载的运算符将要进行的新的操作, 这种操作通常作用在一个类上。 函数operator()可以 不是类的成员函数 是类的成 员函数 类的友元函数
5.3.1类以外的运算符重载 对基本的数据类型,C++提供了许多预定义的运算符,如“+”、“ 等,若有一个复数类 complex: class complex public double real, imag complex(double r=0, double i=o) real=r; imag=i,] 若要把类 complex的两个对象com和com2加在一起,下面的语句 是不能实现的 void maino complex com1(1.1, 2.2), com2 (3.3, 4.4), total; total=com1+com2 ∥错误 错误原因是类 complex的类型不是基本数据类型,而是用户自定义 的数据类型。C++还是无法直接将两个 complex类对象相加
6 5.3.1 类以外的运算符重载 对基本的数据类型,C++提供了许多预定义的运算符,如“+” 、 “- ” 、 “*” 、 “/” 、 “=” 等,若有一个复数类 complex: class complex{ public: double real,imag; complex(double r=0,double i=0) {real=r;imag=i;} }; 若要把类complex的两个对象com1和com2加在一起,下面的语句 是不能实现的: void main() { complex com1(1.1,2.2), com2(3.3,4.4), total; total=com1+com2; //错误 //... } 错误原因是类complex的类型不是基本数据类型,而是用户自定义 的数据类型。C++还是无法直接将两个complex类对象相加
运算符函数 为了表达上的方便,人们希望预定义的内部运算符(如“+”、“-” “米”、“/”等)在特定类的对象上以新的含义进行解释,如希 望能够实现 total=com+com2,这就需要用重载运算符来解决。 C++为运算符重载提供了一种方法,即在进行运算符重载时, 必须写一个运算符函数,其名字为 operator后随一个要重载的运 算符。例如,要重载“+”号,应该写一个名字为 operator+的 函数。 表51运管答函数 函 数 功 能 operator +o 加法 operator-O 减法 operator * 乘法 operator/( 除法 operator <o 小于
7 运算符函数 为了表达上的方便,人们希望预定义的内部运算符(如“+” 、 “-” 、 “*” 、 “/”等)在特定类的对象上以新的含义进行解释,如希 望能够实现total=com1+com2,这就需要用重载运算符来解决。 C++为运算符重载提供了一种方法,即在进行运算符重载时, 必须写一个运算符函数,其名字为operator后随一个要重载的运 算符。例如,要重载“+”号,应该写一个名字为 operator+ 的 函数。 表5.1 运算符函数 函 数 功 能 operator + ( ) 加 法 operator - ( ) 减 法 operator * ( ) 乘 法 operator / ( ) 除 法 operator < ( ) 小 于 ……………… ………………
运算符函数 operator+() 在编译时遇到名为 perator@的运算符函数(@表示所要重教的运 算符),就检查传递给函数的参数的类型。如果编译器在一个运 算符的两边看到自定义的数据类型,就执行用户自己的函数,而 不是常规运算符。 若要将上述类 complex的两个对象相加,只要写一个运算符函数 operator+ complex operator+(complex om1, complex om2) complex temp temp. realom1 real+om2 real; temp. imag=om1 imag+. imag return temp; 我们就能方便的使用语句 total=com1+com2: 将类 complex的两个对象com和com2相加。 也可以使用以下的调用语句,将两个 complex类对象相加: total=operator+(com1, com2); 这两个调用语句是等价的,但显然后者不如前者简明和方便
8 运算符函数operator+() 在编译时遇到名为operator@的运算符函数(@表示所要重载的运 算符),就检查传递给函数的参数的类型。如果编译器在一个运 算符的两边看到自定义的数据类型,就执行用户自己的函数,而 不是常规运算符。 若要将上述类complex的两个对象相加,只要写一个运算符函数 operator+() complex operator+(complex om1,complex om2) { complex temp; temp.real=om1.real+om2.real; temp.imag=om1.imag+om2.imag; return temp; } 我们就能方便的使用语句 total=com1+com2; 将类complex的两个对象com1和com2相加。 也可以使用以下的调用语句,将两个complex类对象相加: total=operator+(com1,com2); 这两个调用语句是等价的,但显然后者不如前者简明和方便
例5.2运算符函数 operator+()将两个 complex类对象相加程序 include class complex public double real: double imad' Void main( [complex com1(1.1, 2.2),com2 (3.3, 4.4), totall, total2 tota1= operator+(com1,com2);∥调用运算符函数 operator+() 的第一种方式 cout<< real1=<<totall, reak<< < imagi="<<totallimag<<endl; tota|2=com1+com2/调用运算符函数 operator+()的第二种方 cout<< real2=<<total2 reak<< < image="<<total2 imag<<endl; 程序运行结果为: real1=4.4 imagi=6.6 real2=4. 4 imag=6.6
9 例 5.2 运算符函数operator+()将两个complex类对象相加程序 #include class complex{ public: double real; double imag; complex(double r=0,double i=0) {real=r;imag=i;} }; complex operator+(complex co1,complex co2) { complex temp; temp.real=co1.real+co2.real; temp.imag=co1.imag+co2.imag; return temp; } Void main() {complex com1(1.1,2.2),com2(3.3,4.4), total1, total2; total1=operator+(com1,com2); //调用运算符函数operator+() 的第一种方式 cout<<"real1="<<total1.real<<” "<<"imag1="<<total1.imag<<endl; total2=com1+com2;//调用运算符函数operator+()的第二种方 cout<<"real2="<<total2.real<<” "<<"imag2="<<total2.imag<<endl; } 程序运行结果为: real1=4.4 imag1=6.6 real2=4.4 imag2=6.6
说明: (1)重载运算符与预定义运算符的使用方法完全相同,它不能改 变原有运算符的参数个数(单目或双目),也不能改变原有的优 先级和结合性。 (2)在C++中,大多数系统预定义的运算符都能被重载,例如 〓 /=% = =|=≤>> >〓 <<==l= &&‖ I new delete 也有一些运算符是不能被重载的,如: 预处理符号#和##也不能重载
10 说明: (1)重载运算符与预定义运算符的使用方法完全相同,它不能改 变原有运算符的参数个数(单目或双目),也不能改变原有的优 先级和结合性。 (2)在C++中,大多数系统预定义的运算符都能被重载,例如 + - * / % ^ & | ~ ! = += -= *= /= %= ^= &= |= > >>= = && || ++ -- [] () new delete 也有一些运算符是不能被重载的,如: . .* :: ?: 预处理符号#和##也不能重载