您好,欢迎访问三七文档
学习目标(1)掌握重载运算符的定义方法。(2)了解运算符重载为成员函数与友元函数的区别。(3)掌握不同类型数据间的转换方法。(4)掌握多态性的概念。(5)掌握虚函数的定义和使用方法。(6)掌握纯虚函数和抽象类的定义。(7)了解面向对象程序设计的基本思想6.1多态性多态性是面向对象程序设计的一个重要特征。多态的是指一个事物有多种状态。多态性可以简单地概括为“一个接口,多种方法”通常我们希望所设计的类具有共同的风格。例如,在不同的类中具有相似功能的函数具有相同的名字、具有相同的参数类型、参数的顺序也相同。这种统一性帮助我们记忆,且有助于新类的设计。在新类的设计中只需要添加相同的数据成员并改写相应的成员函数。不同类的对象调用自己的函数成员,这就是多态性。6.1.1多态的类型在面向对象程序设计语言C++中,多态性的实现方式有4种:重载多态、强制多态、类型参数化多态和包含多态。重载多态和强制多态称为特殊多态性,用来描述语义上无关联的类型间的关系。前面介绍过的函数重载和本章将要介绍的运算符重载都属于重载多态;强制多态就是将一个变量的类型加以强制转换来满足某种操作要求,本章介绍的强制类型转换就属于强制多态。类型参数化多态和包含多态称为一般多态性,用来系统地描述语义上相关的一组类型。包含多态是类族中定义于不同类中的同名成员函数的多态行为,主要是继承过程中通过虚函数来实现,本章介绍的虚函数属于包含多态;类型参数化多态是指当1个函数(或类)对若干个类型参数操作时,这些类型具有某些公共的语义特性,C++中的类模板是实现类型参数化多态的工具,关于类模板的相关内容将在本书中的第7章进行详细介绍。6.1.2静态关联与动态关联从系统实现的角度看,多态性分为两种:静态多态和动态多态。关联(binding)是指捆绑或连接的意思。C++中的多态性与关联这一概念密切相关,一个源程序需要经过编译、连接才能形成可执行的文件,在这个过程中要把调用函数和对应函数连接在一起,这个过程就是关联,又称为绑定。关联就是确定调用的具体对象的过程,一般来说,关联指把一个标识符和一个存储地址联系起来。关联分为静态关联与动态关联。如果在编译程序时就能确定具体的调用对象,称为静态关联;如果在编译程序时还不能确定具体的调用对象,只有在程序运行过程中才能确定具体调用对象,称为动态关联由于静态关联是在程序运行前进行关联的,所以又称为早期关联,而动态关联是在程序运行中进行关联的,也叫作滞后关联。在C++中,采用静态关联与动态关联都能实现多态性,采用静态关联实现的多态称为静态多态,而采用动态关联实现的多态称为动态多态。静态多态在程序编译时系统就能决定调用的哪个函数,因此又称为编译时的多态性。静态多态性是通过函数的重载实现的,以前学过的函数重载和本章将要学习的运算符重载实现的多态性属于静态多态性。动态多态是在程序运行过程中才动态地确定操作的对象,在运行阶段确定关联关系,又称运行时的多态性。本章学习的虚函数实现的多态属于动态多态。6.2运算符重载运算符重载是指对已有的运算符赋予它新的含义,是通过运算重载函数来实现的,本质上也是属于函数重载,是C++实现静态多态的一重要手段。重载是面向对象的基本特点之一。面向对象程序设计的重载:函数重载和运算符重载。函数重载是指在相同作用域内,若干个参数特征不同的函数使用相同的函数名,也称为函数名重载;运算符重载是另一种调用函数的方法,是指同样的运算符可以施加于不同类型的操作数上面,也就是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时产生不同的行为,是一种静态联编的多态。6.2.1什么是运算符重载12问题举例——复数的运算classcomplex//复数类声明{public:complex(doubler=0.0,doublei=0.0)//构造函数{real=r;imag=i;}voiddisplay();//显示复数的值private:doublereal;doubleimag;};运算符重载13问题举例——复数的运算用“+”、“-”能够实现复数的加减运算吗?实现复数加减运算的方法——重载“+”、“-”运算符运算符重载14运算符重载的实质运算符重载是对已有的运算符赋予多重含义必要性C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)实现机制将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。编译系统对重载运算符的选择,遵循函数重载的选择原则。运算符重载6.2.2运算符重载的方法运算符重载实质上是函数的重载。运算符重载函数的一般格式如下:函数类型operator运算符名称(形参表列){对运算符的重载处理}例如,若要对用户定义的类型Complex重载实现加法操作,重载函数原型如下:Complexoperator+(Complex&a,Complex&b);6.2.2运算符重载的方法在定义了重载运算符的函数后,可以说,函数operator+重载了运算符+。在执行复数相加的表达式c1+c2时,系统就会调用operator+函数,把c1和c2作为实参,与形参a,b进行虚行结合,执行函数operator+(a,b)。【例6-1】将运算符“+”重载为适用于复数加法。这里重载函数作为类的友元函数。#includeiostreamusingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}friendComplexoperator+(Complex&a,Complex&b);voiddisplay();private:doublereal;doubleimag;};Complexoperator+(Complex&a,Complex&b){returnComplex(a.real+b.real,a.imag+b.imag);}voidComplex::display(){cout(real,imagi)endl;}intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;coutc1=;c1.display();coutc2=;c2.display();coutc1+c2=;c3.display();}6.2.3重载运算符的规则C++语言对运算符重载进行了以下规定限制:只能重载C++语言中原先已定义的运算符,不能自己“创造”新的运算符进行重载。并不是所有的运算符都可以进行重载。不能进行重载的运算符如下:·.*∷?:Sizeof(长度运算符)不能改变运算符原有的优先级和结合性。C++语言已预先规定了每个运算符的优先级和结合性,以决定运算次序。不能改变其运算次序,如果确实需要改变,只能采用加括号“()”的办法。经重载的运算符,其操作数中至少应该有一个是自定义类型。intoperator+(int,int);//error:不能对内置类型重载+Vectoroperator+(constVector&,constVector&);//ok不能改变运算符对预定义类型数据的操作方式,但是可以根据实际需要,对原有运算符进行适当地改造与扩充。运算符重载有两种方式:重载为类的成员函数和重载为类的友元函数。6.2.4运算符重载为成员函数和友元函数运算符的重载实质上是函数重载,在C++中,运算符重载有两种形式:重载为类的非静态成员函数和重载为非成员函数。如果将运算符重载为类的成员函数,它可以自由地访问本类的数据成员,使用时,总是通过该类的某个对象来访问重载运算符。运算符也可以重载为非成员函数,这时,运算所需要的操作数都需要通过函数的形参表来传递,在形参表中形参从左到右的顺序就是运算符操作数的顺序。如果需要访问运算符参数对象的私有成员,可以将该函数声明为类的友元函数。当运算符重载为成员函数和友元函数时,参数的个数有所不同,具体如下。(1)运算符重载为类成员函数时:参数个数=原操作数个数-1(后置++、--除外)。(2)运算符重载为友元函数时:参数个数=原操作数个数,且至少应该有一个自定义类型的形参。对于双目运算符B,如果将运算符B重载为类成员函数,使之能够实现表达式oprd1Boprd2,其中oprd1为A类对象,则B应被重载为A类的成员函数,形参类型应该是oprd2所属的类型。经重载后,表达式oprd1Boprd2相当于oprd1.operatorB(oprd2);否则,如果将运算符B重载为友元函数,表达式oprd1Boprd2等同于operatorB(oprd1,oprd2),函数的形参代表依自左至右次序排列的各操作数。对于单目运算符,有前置和后置之分。前置单目运算符U,如果将运算符U重载为类成员函数,使之能够实现表达式:Uoprd,其中oprd为A类对象,则U应被重载为A类的成员函数,无形参。经重载后,表达式Uoprd相当于oprd.operatorU();如果将运算符重载为友元函数时,前置单目运算符U重载后,表达式Uoprd等同于operatorB(oprd)。后置单目运算符,如++和--,如果要重载++或--为类成员函数,使之能够实现表达式oprd++或oprd--,其中oprd为A类对象,则++或--应被重载为A类的成员函数,且具有一个int类型形参,用来与前置单目运算符的++oprd和--oprd加以区别。经重载后,表达式oprd++相当于oprd.operator++(0);如果运算符重载为友元函数,则后置单目运算符++和--重载后,表达式oprdB等同于operatorB(oprd,0)。【例6-2】将运算符“+”重载为适用于复数加法。重载函数作为类的成员函数。classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}//friendComplexoperator+(Complex&a,Complex&b);Complexoperator+(Complex&b);voiddisplay();private:doublereal;doubleimag;};//Complexoperator+(Complex&a,Complex&b)//{returnComplex(a.real+b.real,a.imag+b.imag);}ComplexComplex::operator+(Complex&b){returnComplex(real+b.real,imag+b.imag);}voidComplex::display(){cout(real,imagi)endl;}intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;//执行c1.operator+(c2);coutc1=;c1.display();coutc2=;c2.display();coutc1+c2=;c3.display();}C++规定,当重载以下的运算符时,必须重载为某个类的成员函数:=、[]、(),-当重载以下的运算符时,必须是普通函数或友元函数,不能为成员函数:、一般将双目运算符重载为友元函数,单目运算符重载为成员函数。由于友元的使用会破坏类的封装性,因此从原则上说,要尽量将运算符函数作为成员函数。6.2.5重载双目运算符双目运算符(或称二元运算符)是C++中最常用的运算符。双目运算符有两个操作数,通常在运算符的左右两侧,如3+5,a=b,i10等。在重载双目运算符时,在函数中应该有两个参数。下面举
本文标题:第六章多态性.
链接地址:https://www.777doc.com/doc-2087963 .html