浅谈非数值处理问题中C++运算符的重载

时间:2022-08-17 11:52:06

浅谈非数值处理问题中C++运算符的重载

摘要:在利用C++处理非数值问题中,用户自己定义数据类型的情况比较普遍,以至运算符重载问题非常突出,程序设计者只要合理选择运算符重载的形式,正确使用重载格式,就一定能充分发挥运算符重载所带来的编程优势,提高编程的质量。

关键词:C++;运算符;重载

中图分类号:TP312文献标识码:A文章编号:1009-3044(2010)09-2169-03

Talking about the C++ Operator Overloading in the Dealing with Non-numerical Problems

WANG Qiong

(Faculty of Education, Shiyan Radio and Television University, Shiyan 442000, China)

Abstract: In the use of C + + dealing with non-numerical problems, the user-defined data types are more common, as well as operator overloading problem is very prominent, as long as a reasonable choice in the form of operator overloading, the proper use of heavy format, the program designers will certainly be able to give full play to Operator Overloading advantages arising from programming to improve the quality of programming.

Key words: C++; operator; overloading

目前需要计算机处理的问题可以分为数值与非数值两大类,科学和工程计算属于数值处理问题,我们比较熟悉的学生信息管理、工资管理等等这类问题属于非数值处理问题。这两大类问题所处理数据的类型区别比较明显,在数值处理问题中,数据的类型相对简单,多为整型、实型等基本数据类型,而在非数值处理问题中,数据多为记录、文件等比较复杂的形式,需要用户根据所处理问题的具体情况来定义其类型。c++语言中预定义的运算符的操作对象只能是基本数据类型,在非数值处理问题中,对于用户自定义的数据类型也需要进行各种运算,这就需要对已有运算符进行重载,使它们具有处理用户自定义的数据类型的能力。

1 非数值处理问题中运算符重载问题的提出

在利用C++开发非数值处理问题的软件过程中,数据类型的定义及对数据的处理可以在不同的类中实现。为了便于叙述,在本文中分别称呼它们为数据类和数据处理类。

在数据处理类中,我们往往会对数据进行抽象,将侧重点放在数据的逻辑结构和存储结构的选择上,进而按照结构化、模块化以及面向对象的程序设计方法设计出比较满意的算法(程序)。我们所关注的是在算法实现过程中如何体现出数据之间的关系(逻辑结构),而并不关心数据本身究竟是什么情况,比如在程序设计过程中会使用ElemType之类的标识符来表示数据的类型,在程序开始部分使用C++语言中的typedef语句将ElemType定义为实际的数据类型。

由于数据处理类并不关心数据的类型,所以在算法中会将其作为简单类型处理,大胆使用输入/输出、算术、关系、赋值等运算符,至于运算符的重载问题会抛给数据类处理。

2 运算符重载时形式的选择

在C++中,只有类的成员函数和类的友元函数才能够访问类的私有数据成员,因此只有将运算符重载为数据类的成员函数或是友元函数时,才能使被重载的运算符应用于新的数据类型。在对某个运算符进行重载时,究竟是将其重载为成员函数还是友元函数,是我们首先要弄清楚的问题。

2.1只能重载为成员函数的运算符

C++要求,像赋值“=”、下标“[]”、调用“()”、以及成员访问箭头“->”等,这些第一个操作数一定是本类对象的运算符,重载时必须被定义为类的成员函数,任何把这些运算符重载为非类成员函数的做法都会产生编译时刻的错误。这样做的原因在于类的所有非静态成员函数都隐含有指向对象自己的this指针(类的友元函数不具有),如果将运算符重载为类的成员函数,则运算符的第一个操作数系统默认就是this对象(本类的对象)。

也正是由于this指针的存在,当运算符被重载为成员函数的形式时,第一个操作数不作为函数参数,这样一来,对于单目运算符可以不写参数,而双目运算符可以只写一个参数,即第二个操作数(或称右操作数)。

运算符重载为成员函数格式如下:

operator ();

例如有一个表示时间的time类,求将已有时间推后x小时后的时间,重载“+”运算符为time类的成员函数,格式如下:

time operator + (int x);

2.2 只能重载为友元函数的运算符

与第1)种情况正好相反,像插入运算符“”等第一个操作数一定不是本类对象的运算符,只能被重载为类的友元函数。比如插入运算符“” 的第一个操作数 cin是系统定义类istream类的全局对象。

当运算符被重载为友元函数的形式时,函数参数的个数与运算符操作数的个数一致,即单目运算符需要一个参数,而双目运算符需要两个参数。

运算符重载为友元函数格式如下:

friend operator ();

同样以1)中的time类为例,重载“+”运算符为time类的友元函数,格式如下:

firend time operator + (time& t,int x);

2.3 根据应用情况选择重载形式的运算符

分析1)、2)两种情况,之所以某些运算符只能重载为成员函数或是友元函数,是由这些运算符的第一个操作数的类型决定的,第一个操作数一定是本类对象的运算符,重载时必须被定义为类的成员函数,第一个操作数一定不是本类对象的运算符,只能被重载为类的友元函数。如果对运算符的第一个操作数的类型没有限制,那么这个运算符既可以被重载为成员函数,也可以被重载为友元函数。

在具体选择运算符的重载形式时,可以根据应用情况来决定。双目运算符,如算术运算符“+”、“-”,关系运算符“>”、“

3 非数值处理问题中C++运算符重载实例

下面我们以编写一个简单的商品库存表管理程序为例,来分析在运算符重载过程中要注意的问题。

3.1 类的设计

我们计划用线性表来管理一个商品库存表,为简单起见,只作如下要求:

1) 每个商品记录包含有四项内容:商品代号、商品名称、最低库存量和当前库存量。

2) 可对商品库存表进行记录的添加、遍历(显示输出)。

本程序要处理的数据是商品记录,定义一个商品类(goods),专门用于描述商品情况及因商品这一新的类型而引发的操作。

由于采用线性表管理商品库存表,还需定义一个线性表类(List),实现对记录的添加、遍历(显示输出)。

3.2 类的实现

在VC++6.0中,创建一个名为“商品库存表管理程序”控制台应用程序,插入两个普通类:List和goods。

对于goods类,我们很快就确定下来它的四个数据成员:

char code[5]; //商品代号

char name[15]; //商品名称

int minq; //最低库存量

int curq; //当前库存量

List类是非常容易实现的,若线性表采用顺序存储结构,则数据成员即为一个存储线性表元素的数组及一个存储线性表长度的整型变量。按照设计要求,List类只包含初始化(InitList())、插入(InsertList())、遍历(TraverseList())三个操作。

List.h中的主要代码如下:

#include"goods.h"

typedef goods ElemType;

class List

{ElemType*list; //存线性表元素的动态存储空间的指针

int size;//存线性表长度

int MaxSize; //规定list数组的长度

public:

void InitList(); //初始化线性表

bool InsertList(); //向线性表中插入元素

void TraverseList(); //遍历线性表

};

List.cpp中的主要代码如下:

#include

#include "List.h"

void List::InitList() //初始化线性表

{MaxSize=10; list=new ElemType[MaxSize]; size=0;

}

bool List::InsertList(ElemType item) //向线性表中插入元素

{ElemType item;

cout

cin>>item;

int pos=0;

for(int i=0;i

{if(item==list[i]){cout

if(item

}

for(i=size-1;i>=pos;i--) list[i+1]=list[i];

list[pos]=item;

size++;

return true;

}

void List::TraverseList() //遍历一个线性表

{for(int i=0;i

cout

cout

}

为了便于讨论,向线性表中插入元素只考虑了插入到有序表中的情况。

对List.cpp进行编译,马上就会报错显示“>>”、“

根据我们前面的分析,“>>”、“

goods.h中的主要代码如下:

#include

class goods

{

char code[5]; //商品代号

char name[15]; //商品名称

int minq; //最低库存量

int curq; //当前库存量

public:

friend istream& operator >> (istream& in,goods& g);

friend ostream& operator

bool operator==(goods& g); //重载运算符"=="

bool operator

};

goods.cpp中的主要代码如下:

#include

#include "goods.h"

istream& operator>>(istream & in,goods & g)

{coutg.code;

coutg.name;

coutg.minq;

coutg.curq;

return in;

}

ostream& operator

{out

return out;

}bool goods::operator==(goods& g)

{return (strcmp(code,g.code)==0);

}

bool goods::operator

{return (strcmp(code,g.code)==-1);

}

3.3 程序测试及对运算符重载时要注意的问题

编写一个非常简单的主程序main.cpp来测试我们所设计的类,代码如下:

#include"List.h"

void main()

{

List l;

l.InitList();

l.InsertList();

l.TraverseList();

}

程序运行结果如图1所示。

从运行结果显示,我们所编写的程序实现了设计要求,当然这个程序的功能与现实中的要求相差甚远,至少商品库存表应该保存在文件中,限于篇幅,这里不再讨论。

在以上的实例中,我们重载了四个运算符,从goods.h和goods.cpp中,我们可以清楚地看出将运算符重载为类的成员函数和友元函数在声明及实现时的格式区别,这是我们在编程时要注意的问题之一。另外,当友元函数不属于某个类时,它的身份同main()函数一样是全局函数,放置位置可以很灵活,比如在本实例中,“>>”与“”与“

4 结束语

在非数值处理问题中,由于新的数据类型的出现,运算符重载问题非常普遍,我们只要合理选择运算符重载的形式,正确使用重载格式,就一定能充分发挥运算符重载所带来的编程优势,提高编程的质量。

参考文献:

[1] 徐孝凯.数据结构使用教程[M].2版.北京:清华大学出版社,2006.

[2] 李龙澍.C++程序设计[M].北京:清华大学出版社,2003.

[3] 杨剑炉.C++中运算符重载的几种方法的适用性探讨[J].赤峰学院学报:自然科学版,2009(12).

上一篇:可变虚拟数据在Excel函数教学中的应用 下一篇:一种在.NET下实现的全新日课表编排算法