运算符重载概述
什么是运算符重载
运算符重载:用同一个运算符完成不同的运算功能。
C++运算符重载的相关规定如下:
1.不能改变运算符的优先级。
2.不能改变运算符的结合性。
3.默认参数不能和重载的运算符一起使用,也就是说,在设计运算符重载成员函数时不能使用默认函数。
4.不能改变运算符的操作数的个数。
5.不能创建新的运算符,只有已有运算符可以被重载
6.运算符作用于C++内部提供的数据类型时,原来含义保持不变
C++中可被重载的运算符:
C++中不能被重载的操作符
运算符重载函数的定义格式
运算符重载函数作为类的成员函数
函数类型 operator 重载运算符(形参表)
{
函数体;
}
运算符重载函数作为类的友元函数
friend 函数类型 operator 重载运算符(形参表)
{
函数体;
}
其中,“函数类型”指出重载运算符的返回值类型,operator是定义运算符重载函数的关键词,“重载运算符”指出要重载的运算符名字,是C++中可重载的运算符,比如要重载加法运算符,这里直接写“+”即可,“形参表”指出重载运算符所需要的参数及其类型。
##重载单目运算符
重载“++”和“–”运算符
“++”和“–”重载运算符也有前缀和后缀两种运算符重载形式,以“++”重载运算符为例,其语法格式如下:
函数类型 operater ++()
函数类型 operater ++(int)
例:
#include
using namespace std;
class MyClass2
{
int n;
public:
MyClass2(int i){ n = i; }
int operator ++(){ n++; return n; }
int operator ++(int){ n += 2; return n; }
void display()
{
cout << "n=" << n << endl;
}
};
void main()
{
MyClass2 A(5), B(5);
A++;
++B;
A.display();
B.display();
system("pause");
}
输出结果为:
注:在上述程序中,定义了前缀++和后缀++重载运算符,在main()中,语句A++调用了后缀重载运算符,语句++B调用前缀重载运算符。
重载->运算符
“->”运算符是成员访问运算符,这种单目运算符只能被重载为成员函数,一般成员访问运算符的时运格式如下:
对象->成员
成员访问运算符“->”函数重载的一般形式为:
数据类型 类名::operator->();
例:
class PClass
{
int n; double m;
public:
PClass *operator->()
{
return this;
}
void setvalue(int n1, double m1)
{
n = n1; m = m1;
}
void disp()
{
cout << "n=" << n << ",m=" << m< } }; void main() { PClass s; s->setvalue(10, 20.5); s->disp(); s.setvalue(20, 89.8); s.disp(); system("pause"); } 结果: 注:上述程序中,重载“->”运算符的成员函数,该函数返回当前对象的指针。从而导致“s->disp();”和“s.disp();”两个语句都是正确的,实际上,前者通过调用重载“->”运算符成员函数转换成后者的格式。 重载双目运算符 重载双目运算符为成员函数 假设有一个类A,对于双目运算符op,如果重载运算符op使之能够实现表达式“obj1 op obj2”,其中obj1和obj2均为A类的对象。 若把op重载为A类的成员函数,该函数只有一个形参,形参的类型是obj2所属的类型。经过重载之后,表达式“obj1 op obj2”解释为: obj1.operator op(obj2) 左边的Obj1通过this指针传递,右边的对象obj2由参数传递。 重载双目运算符为友元函数 假设有一个类A,对于双目运算符op,如果重载运算符op使之能够实现表达式“obj1 op obj2”,其中obj1和obj2均为A类的对象。 若把op重载为A类的友元函数,该函数有两个形参,经过重载之后,表达式“obj1 op obj2”解释为: obj1 op(obj1,obj2) 左右两个对象obj1,obj2都由参数传递。 下面是重载运算符为成员函数和重载为友元函数的对比: 例: 重载运算符为成员函数: #include using namespace std; class vector { int x, y; public: vector(){ };//默认构造函数 vector(int x1, int y1)//重载函数 { x = x1;y=y1; } vector operator+(vector v) { vector tmp; tmp.x = x + v.x; tmp.y = y + v.y; return tmp; } vector operator-(vector v) { vector tmp; tmp.x = x - v.x; tmp.y = y - v.y; return tmp; } void display() { cout << "(" << x << "," << y << ")"; } }; void main() { vector v1(2, 3), v2(3, 5), v3, v4; cout << "v1:"; v1.display(); cout << "v2:"; v2.display(); v3 = v1 + v2; v4 = v1 - v2; cout << "v3:"; v3.display(); cout << "v4:"; v4.display(); system("pause"); } 重载运算符为友元函数: #include using namespace std; class vector { int x, y; public: vector(){ };//默认构造函数 vector(int x1, int y1)//重载函数 { x = x1; y = y1; } friend vector operator+(vector v, vector v1) { vector tmp; tmp.x = v1.x + v.x; tmp.y = v1.y + v.y; return tmp; } friend vector operator-(vector v, vector v1) { vector tmp; tmp.x = v1.x - v.x; tmp.y = v1.y - v.y; return tmp; } void display() { cout << "(" << x << "," << y << ")"; } }; void main() { vector v1(2, 3), v2(3, 5), v3, v4; cout << "v1:"; v1.display(); cout << "v2:"; v2.display(); v3 = v1 + v2; v4 = v1 - v2; cout << "v3:"; v3.display(); cout << "v4:"; v4.display(); system("pause"); } 注意:重载运算符为成员函数和友元函数时关键的区别在于成员函数具有this指针,而友元函数没有this指针。 重载比较运算符 比较运算符函数重载必须返回true(非0)和false(0)。 重载赋值运算符 重载“+=”和“-=”运算符 程序中重载运算符“+=”和“-=”与标准数据类型“+=”和“-=”不完全相同。调用重载的运算符时,例如V1+=V2,并不改变V1的值,而后者会改变运算符左边的值。 #include using namespace std; class vector { int x, y; public: vector(){ } vector(int x1, int y1) { x = x1; y = y1; } friend vector operator+=(vector v1, vector v2)//友元函数方式实现 { vector tmp; tmp.x = v1.x + v2.x; tmp.y = v1.y + v2.y; return tmp; } vector operator-=(vector v)//成员函数方式实现 { vector tmp; tmp.x = x - v.x; tmp.y = y - v.y; return tmp; } void display(){ cout << "(" << x << "," << y << ")"< }; void main() { vector v1(3, 2), v2(6, 5), v3, v4; v1.display() ; v2.display(); v3 = v1 += v2; v4 = v2 -= v1; v3.display(); v4.display(); v1.display(); v2.display(); system("pause"); } 可以看出,重载+=与-=运算符中,v1+v2的运算不改变v1的值。 重载=运算符 赋值运算符=的原有含义是将赋值号右边表达式的结果复制给赋值号左边的变量,通过运算符=的重载将赋值号右边的数据成员函数依次复制给左边对象的数据成员中。 重载下标运算符 下标运算符“[ ]”通常用于获取数组的某个元素,重载下标运算符可以实现数组下标的越界检测等。下标运算符重载只能作为类的成员函数,不能作为类的友元函数。 //设置一个Assoc类,其中用一个数组表示每个单词的情况,而且每个单词除了他出现的次数, //还应保存该单词本身,因此定义一个结构。该类中有一个重载运算符“[ ]”成员函数,用来返回 //某个单词已经出现的次数,返回值是一个引用,可用于改变值。在每查找到一种单词后返回以出 //现的次数在运算符后边进行++运算,相对于返回值++,间接地起到每找到一个单词便将它的出现次数 //+1的目的。 #include #include using namespace std; struct Pair//说明结构体类型 { char *name;//单词 int num;//出现的次数 }; class Assoc { struct Pair *vec;//指向结构体变量的指针 int size;//分配总的单元个数 int used;//已使用的单元个数 public: Assoc(int m)//构造函数 { size = (m > 16) ? m : 16;//size至少大于16 used = 0; vec = new Pair[size];//分配空间 } int & operator [] (char *); void disp(); }; int & Assoc::operator[](char *p)//返回的是pp->num的引用 { struct Pair *pp; for (pp = vec; pp < vec + used; pp++)//在已有的单词中查找 if (strcmp(p, pp->name) == 0)//若找到返回次数 return pp->num; pp = &vec[used++];//在已有的单词中未找到,则使用的单元个数+1 pp->name = new char[strlen(p) + 1];//分配一个单元空间 strcpy(pp->name, p); pp->num = 0; return pp->num;//返回0 } void Assoc::disp() { cout << "单词出现次数统计:" << endl; for (int i = 0; i < used; i++) { cout << " " << vec[i].name << ":" << vec[i].num << "次" << endl; } } void main() { char buf[16]; Assoc vecc(20);//设置20个单元存放单词 int k = 10; cout << "请输入" << k << "个单词" << endl; for (int i = 0; i < k; i++) { cout << "第" << i + 1 << "个单词:"; cin >> buf; vecc[buf]++;//调用“[]”,并将该单词出现次数增1 } vecc.disp(); system("pause"); } 重载new和delete运算符 new和delete只能被重载为类的成员函数,不能重载为友元。而且,无论是否使用关键字static进行修饰,重载了的new和delete均为类的静态成员函数。 运算符new重载的一般格式如下: void *类名::operator new(size_t,参数表); 在带有“参数表”时,应注意使用重载new的方式。例如,若有一个类X有如下重载new的成员函数: void* operator new(size_t size,int x,int y,int z) {…… } 则使用重载new的方式如下: x*pX=new(1,2,3) X; 运算符delete重载的格式一般如下: void *类名“::operator delete(void*,参数表); 重载类型转换运算符 重载类型转换运算符格式: operator 类型名() { 函数体; } 类型转换运算符没有返回类型,因为类型名就代表了它的返回类型,而且没有任何参数。 转换运算符重载的缺点是无法定义其类对象运算符操作的真正含义,因为只能进行相应的对象成员数据和一般数据变量的转换操作。 重载函数调用运算符 函数调用运算符“()”只能说明成类的非静态成员函数,该函数具有以下的一般格式: 函数类型 类名::operator()(参数表) 与普通函数一样,重载了的函数调用运算符可以事先带有零个或多个参数,但不得带缺省的参数。 #include using namespace std; class PClass { public: double operator()(double x, double y) const; double operator()(double x) const; }; double PClass::operator()(double x, double y)const { if (x < y) return (y); else return (x); } double PClass::operator()(double x) const { if (x < 0) return (-x); else return (x); } void main() { PClass fun; cout << fun(1.2, 2.3) << endl; cout << fun(-6) << endl; system("pause"); }