admin 管理员组

文章数量: 1086019


2024年12月31日发(作者:游戏开发需要学多久)

维普资讯

2002年第2期 

第5卷(总15期) 

西安联台大学学报 

Jourr ̄l ofXi’all United Umver ̄ty .5 No 2 

Apr.2002 

文章编号:1008—777X(2002}02 0060—05 

面向对象程序设计语言C++中多态性的实现方式 

张莉 

(陕西师范大学计算机科学学院,陡西西安710062) 

摘要:多态性是面向对象程序设计语言C++的重要概念之一本文详细讨论了在c++中多态 

性的4种实现方式、各自的特征以及在程序设计中的应用,最后对这4种实现方式进哥亍了比较 

关键词:多态性;类;虚函数;模板;重载 

中图分类号:TIP 311.11 文献标识码:A 

多态性是面向对象程序设计的一太支柱,它指的是在基类中定义的属性或服务被派生类继承之后, 

可 表现出不同的行为.也就是指一段程序能够处理不同类型对象的能力在面向对象程序设计语言 

c++中,这种多态性的实现方式有4种,分别是强制多态、重载多态、类型参数化多态和包含多态其 

中,类型参数化多态和包含多态称为一般多态性,用来系统地描述语义上相关的一组类型;强制多态和 

重载多态称为特殊多态性,用来描述语义上无关联的类型间的关系下面详细介绍这4种多态性的具体 

应用. 

1 包含多态 

在C++中公有继承关系是一种包含关系派生类直接公有继承基类定义中的属性或服务,如果1 

个程序段既能处理基类的对象也能处理基类的派生类的对象,该程序段称为多态程序段c++采用虚 

函数实现包含多态 一个函数一旦声明为虚函数,在编译阶段,编译器并不按照它的静态类型为它生成 

调用此函数的版本,而只为它生成虚函数表(表中存放与此函数同名、同参数、同返回值的虚函数的地 

址).在程序运行时,再根据实际对象的类型,查虚函数表,找出相应版本的函数后,才能使用它因此,这 

种不是在编译阶段而是在运行阶段动态确定应使用哪一个虚函数的方式叫动态束定. 

要把一个函数声明为虚函数,只要在原函数的声明之前加上virtul关键字即可利用虚函数进行动 

态束定,必须用指向基类的指针或引用来访问它,这是因为C++是类型系统,在编译阶段,C++的变 

量名或函数名就与相应的存储单元联系起来,使用名字也就是使用对应的存储单元.这有利于检查类型 

系统,并可产生高效代码.但这种类型的限制缺乏灵活性,不能在运行时改变名字的含义,然而多态要求 

在不同的上下文中,同一名字有多种含义,C++引入虚函数的目的是告诉编译器在运行时才能确定要 

调用哪一个虚函数 为了把变量名与相应的存储单元分开,它用指针来调用虚函数.这样,只要改变指针 

所存地址的值,也就间接地改变了调用对象.例: 

#include<iostream.h> 

P] ̄tss Point //定义基类P0_nt 

{priam: 

loatf x,y; 

bl|c: 

收稿日期:2001 09—20 

作者简介:张莉(1969一),女,陕西西安人,陕西师范大学计算机科学学院讲师,西北大学硕士研究生 

维普资讯

第2期 张莉:面向对象程序设计语言C++中多态性的实现方式 61 

Point(){t; 

Point{lfoat i,lfoat J) 

t x=i: 

y=j;J 

virtulfloat area() 

//胄明为虚函数 

【retqlfli-ii O.0;}}; 

const float Pi:3.141593; 

class Circle:public Point 

/健义派生类Circle 

{private: 

loatf radius; 

public: 

Cirde{lfoat r) 

{radius r:{ 

virtUE]float area() 

【returnPi*radius*radius;】J; 

voidmain() 

f Point PP; 

Circle c(5.4321): 

pp=&c: 

//} 向基类的指针PP 

 ̄out<<pp->area()<<emil;l // ̄15虚函数,执行派生类中定义的函数area() 

从上面例子可看出,利用虚函数可在基类和派生类中使用相同的函数名定义函数的不同实现

从而 

实现“一个接口,多种方式”一般说来,外部函数不能声明为虚函数,成员函数(除构造函数)都可以声明 

为虚函数.然而,在处理虚函数时,要动态确定应该选用哪一版本函数,故它比标准函数需要更多的存储 

空间.因此,虚函数仅用于处理派生类中一系列同名、同参数和同返回值的函数 

2 类型参数化多态 

类型参数化多态是指当1个函数(或类)对若干个类型参数操作时,这些类型具有某些公共的语义 

特性,可以用该函数(或类)来描述这些公共语义特性.C++中的模板是实现类型参数化多态的工具

分为类模板和函数模板 

, 

2 1 类模板 

个类模板可以表示一组类下面是一个通用栈类,它可以存放整数、字符或类对象

//slack类模板 

. 

#include<stdh'b.h> 

template<classT>class stack 

{T v; 

T p; 

int疆: 

public: 

slack【int s){v:p:口 T[sz=s】;J 

stack()fdelete【h;】 

void pmh(T a)【 P++=a;j 

Tpop(){retIJm 

oivdmain() 

{stack<ch盯>sch{20); 

stack<int>si(2o); 

//stack类模板用char实伪化后创建对象 

//stack类模板用int实例化后创建对象 

P:I 

int size()const【return p-v;}】 

sch.push(’a’); 

si.push(10); 

维普资讯

西安联合大学学报 第5卷 

其中,stack类模板中带有一个类型参数T,表示栈中存放对象的类型,它不是实际类型,因此不能 

用类模板直接生成实例对象.通过对类模板的实例化(即给类模板的参数指定具体类型的过程),类模板 

实例化后的结果是类而不是实例对象,因此可用类模板实例化后的结果类产生实例对象.在main()函 

数中,从stack类模板实例化了两个模板类:stack<char>和stack<int>,然后又由这两个模板类分别 

实例化各自对象:sch和si. 

2.2 函数模板 

与类模板相似,可以定义操纵一组类型的函数.下面定义了一个求两对象间的最大值的函数模板 

template<classT>Tmax(T a,T b){retllm a>b?a:b;} 

该函数模板可以求int,char,float指针或任何重载了>运算符的类对象间的最大值.函数模板也 

要实例化,实例化后就生成了具体的函数代码(即特定于参数的类型),与类模板不同的是,它的实例化 

不需要用户显式进行,而是在函数调用时由编译器来处理.例如: 

tnt a,b; 

char c。d; 

intmI=max(a,b); 

i nlm2=max(c,d); 

//fl用Inax(int a。int b); 

/,调用max(char c。char d) 

事实上,函数模板表示了一组名字相同的函数,这些函数之间以及这些函数与其它同名函数之间是 

重载函数的关系.在使用函数模板时,应保证函数的参数与模板函数的参数正好相配,因为编译器不会 

给模板函数的参数提供任何形式的转换. 

总之,模板描述了一组类或一组函数,避免了为各种不同的数据类型进行重复的编码工作. 

3 重载多态 

重载是多态性中最简单的形式它是指用同一名字表示不同的函数或运算符,从而使C++具有更 

大的灵活性和扩展性它分为运算符重载和重载函数两种. 

3.1 重载函数 

重载函数是指同一作用域内名字相同、但参数不同的函数例如: 

薯|nclutle<iostream.1a> 

tntfunc(int X。int Y)1 rea ̄x<y?y:tx;l 

lfoat func(lfoat x。flato Y){return x<y7 y:x:} 

double rune(double X。double Y)Irctlll ̄x(y?y:x l 

void llll ̄llt() 

{intlit1=8。n2=10; 

tout<<“the max is:”<<rune(at。n2)<<endl; 

floatml=4.3。floatm2=2.6: 

c ̄ut<<“thelllaxis:”<<func(nd。m2)<<endl; 

double fl=2.0。12=4.9: 

cout<<“themax is:”<<f ̄mc(fl,f2)<<endl;j 

运行结果为: 

theillaxis:10 

hemaxits:4.3 

the nlaxis:4.9 

上述3个函数,函数名相同,函数参数不同,因为编译器是根据参数来识别重载函数,所以必须保证 

重载函数的参数有所不同,即两重载函数必须具有以下两种差别之一才能分辨 

(1)函数的参数个数不同; 

(2)一个或多个参数的类型不同. 

维普资讯

第2期 张莉:面向对象程序设计语言C++中多态性的实现方式 63 

3.2 运算符重载 

c++的基本类型(int,char,float等以及它们的派生类型)既能描述数据的存储格式,又能描述施 

加在数据上的操作,这种操作用运算符来指定在基本类型中运算符都按系统预定义好的方式来工作 

为了使用户定义的类型与基本类型一样,C++也允许用户定义类型使用运算符来表示操作实质上, 

运算符可以看成是一种函数,即运算符函数,只是对于基本类型,函数都是编译器给定的,不能加以改 

动.但对于类对象,用户却可以重新定义运算符函数,以便设置运算符在类对象中新的含义.因此,定义 

运算符在某类对象操作的做法即所谓的运算符重载. 

运算符函数可以是类的成员函数,也可以是非成员函数,如果是非成员函数,一般将它声明为该类 

的友员.例: 

class ̄ ̄aplex 

『//… 

public: 

/愎数类 

CompIex operator+ccmln Complex&cam) 

{Complex temp(rpart+cⅫ.rpart.ipart+corn.ipart): 

l nImlamp;l 

//...】; 

运算符函数operator+被定义为公有的,程序中的其它函数可以调用它,在定义了该函数之后,就 

可以像基本类型一样对复数对象用+表达式实施运算.当程序中有语句 

Cmnplex a(10.7).b{3。5).c; 

c=a+b: 

时,C++编译器把表达式a+b解释为函数调用a.operator+(b),在调用时,operator+成员函数首先创 

建一个临时Complex类对象temp,然后把出现在加法表达式中的两个复数之和暂存其内,最后将这个 

临时对象返回. 

4 强制多态 

强制也称类型转换,是指将一种类型的值转换成另一种类型的值而进行的语义操作,从而防止类型 

错误.类型转换可以是隐式的,在编译阶段完成;也可以是显式的,在运行阶段完成 

4 1 基本数据类型之间的类型转换 

c++定义了基本数据类型之间的转换原则,即 

char shortint unsignedlong unsinegdlongflato doublelong double 

高 

当两个操作对象类型不一致时,在算术操作之前级别低的自动转换成级别高的类型 

上述规则不适用于赋值操作.当赋值运算符右端的类型与左端的类型不同时,右端的值要转换成左 

端类型.然后将转换后的值赋值给左端. 

类型转换可以使用下面3种强制类型转换表达式,从而可以改变编译器所使用的规则,可以按程序 

员自己的意愿进行所需的类型转换 

(1)static-east<T>(E); 

(2)T(E); 

(3)(T)E; 

其中,E表示一个运算表达式,T表示一个类型表达式,第三种表达式是C语言中所使用的风格,在 

C++中,建议不要使用,应选择使用第一种形式.例如:设对象f的类型为double,且其值为5.26.则表 

达式static-cast<int>(f)的值为5,类型为int 

4.2 用户定义类型的转换 

着重介绍类类型与其它数据类型之间的转换 

(1)在c++中.把其它数据类型转换成类对象是通过转换构造函数来完成的要求的前提是此类 

维普资讯

西安联台大学学报 第5卷 

的转换构造函数是只带1个非缺省参数的构造函数 

(2)把类对象转换成其它数据类型是通过转换运算符函数来完成的.它是一种类似显示类型转换的 

机制,它的设计需要注意两点:第一,转换运算符函数必须是类的成员函数;第二,转换运算符函数投有 

参数和返回值. 

例: 

da integer 

{inti: 

public: 

intgeer(int a)//转换构造函数.把int a转换为类对象 

{i=a:} 

operator int() //转换运算符函数,把类对象转换为整型数 

{t-e ̄m'ni;} 

上例可以在integer类对象与整型数之问相互转换. 

integeril(1 0],e{20); 

int a=il;

il=a;

//使用转换运算符函数.将类对象j1转换为int后.再进行赋值 

//使用转换构造函数,将int a转换为intgeer类对象后喊蛤il; 

i2=10+il*2;//由于没有重载*运算符.所以首先把il通过转换运算符函数转换为_mt后与2进行整数乘 

法运算,然后与整数10进行整数加法运算.最后使用转换构造函数把最终结果转换为integex 

类对象后赋蛤也. 

借助用户定义的类型转换,可以在多种不同类型对象之间进行混合运算,然而强制类型使类型检查 

复杂化,尤其在允许重载的情况下,可能会产生二义性.因此,在程序设计中要注意避免由于强制带来的 

二义性. 

从上面可看出,一般多态性是真正的多态性,特殊多态性只是表面的多态性.因为重载只允许某一 

个符号有多种类型,而它所表示的值分别具有不同的类型.类似地,隐式类型转换也不是真正的多态,因 

为在运算开始前.各值必须转换为所要求的类型,而输出类型也与输人类型无关相比之下,振生类与继 

承却是真正的多态,类型参数化也是一种纯正的多态,同一对象或函数在不同的类型上下文中统一使用 

而不需采用隐式类型转换、运行时检测或其它限制. 

[参考文献】 

[1]邵维忠.杨芙清.面向对象的系统分析[M].北京:清华大学出版杜,1998 

[2]麦中凡.c++程序设计语言教程(语言基础)[M]北京:北京航空航天大学出版社,1995 

[3] 肖基毅.面向对象程序设计中的多态性研究[J]微计算机应用1999,20(3) 

[4] 蓝雯飞.c++中的多态性及其应用[-1]计算机时代1998(7) 

[责任编辑马云彤] 

Realization of Polymorphism in 0bjected-oriented Programming C++ 

ZHA=NG 

(College 0f Computer Science,Shaanxi Normal Umv,Xi’an 710062,Chim) 

Abstract:Polymorphisaa is one of the important conceptions 0f Objected-oriented Programming C++. 

Four realization methods of Polymorphism,their characteristics and applications are discussed in compari一 

8or1. 

Key words:Polymorphism;Class;Virtual Function;Temp[ate;Overloading 


本文标签: 函数 类型 对象 运算符 使用