运算符函数的定义与其他函数的定义类似,惟一的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的。运算符函数定义的一般格式如下:

<返回类型说明符> operator <运算符符号>(<参数表>)
{
//函数体
}

运算符重载时要遵循以下规则:

(1) 除了类属关系运算符"."、成员指针运算符".*"、作用域运算符"::"、sizeof运算符和三目运算符"?:"以外,C++中的所有运算符都可以重载。

(2) 重载运算符限制在C++语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。

(3) 运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。

(4) 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。

(5) 运算符重载不能改变该运算符用于内部类型对象的含义。它只能和用户自定义类型的对象一起使用,或者用于用户自定义类型的对象和内部类型的对象混合使用时。

(6) 运算符重载是针对新类型数据的实际需要对原有运算符进行的适当的改造,重载的功能应当与原有功能相类似,避免没有目的地使用重载运算符。

  运算符函数重载一般有两种形式:重载为类的成员函数和重载为类的非成员函数。非成员函数通常是友元。(可以把一个运算符作为一个非成员、非友元函数重载。但是,这样的运算符函数访问类的私有和保护成员时,必须使用类的公有接口中提供的设置数据和读取数据的函数,调用这些函数时会降低性能。可以内联这些函数以提高性能。)

重载为成员函数

 <函数类型> operator <运算符>(<参数表>)
{
//函数体 }

当运算符重载为类的成员函数时,函数的参数个数比原来的操作数要少一个(后置单目运算符除外),这是因为成员函数用this指针隐式地访问了类的一个对象,它充当了运算符函数最左边的操作数。因此:

(1) 双目运算符重载为类的成员函数时,函数只显式说明一个参数,该形参是运算符的右操作数。

(2) 前置单目运算符重载为类的成员函数时,不需要显式说明参数,即函数没有形参。

(3) 后置单目运算符重载为类的成员函数时,函数要带有一个整型形参。

    调用成员函数运算符的格式如下:

    <对象名>.operator <运算符>(<参数>)

    它等价于

    <对象名><运算符><参数>

    例如:a+b等价于a.operator +(b)。一般情况下,我们采用运算符的习惯表达方式。

#include <iostream>
#include <cmath>
using namespace std;
class Complex
{
public:
Complex();
Complex(double r,double i);
Complex operator+(Complex &c1);
Complex operator-(Complex &c1);
Complex operator*(Complex &c1);
Complex operator/(Complex &c1);
void display();
private:
double real;
double imag;
}; Complex::Complex(double r,double i):real(r),imag(i){} Complex::Complex()
{
real=;
imag=;
} Complex Complex::operator+(Complex &c1)
{
return Complex(real+c1.real,imag+c1.imag);
} Complex Complex::operator-(Complex &c1)
{
return Complex(real-c1.real,imag-c1.imag);
} Complex Complex::operator*(Complex &c1)
{
return Complex(real*c1.real+(-imag*c1.imag),real*c1.imag+imag*c1.real);
} Complex Complex::operator/(Complex &c1)
{
return Complex((real*c1.real+imag*c1.imag)/(c1.real*c1.real+c1.imag*c1.imag),
(imag*c1.real-real*c1.imag)/(c1.real*c1.real+c1.imag*c1.imag));
} void Complex::display()
{
if(imag>)
cout<<"("<<real<<"+"<<imag<<"i)"<<endl;
else if(imag==)
cout<<"("<<real<<")"<<endl;
else
cout<<"("<<real<<"-"<<fabs(imag)<<"i)"<<endl;
} int main()
{
Complex c1(,),c2(,-),c3,c4,c5,c6;
c3=c1+c2;
cout<<"c1=";
c1.display();
cout<<"c2=";
c2.display();
cout<<"c1+c2=";
c3.display();
c4=c1-c2;
cout<<"c1-c2=";
c4.display();
c5=c1*c2;
cout<<"c1*c2=";
c5.display();
c6=c1/c2;
cout<<"c1/c2=";
c6.display();
return ;
}

友元函数运算符

friend <函数类型> operator <运算符>(<参数表>)
{
//函数体
}

当运算符重载为类的友元函数时,由于没有隐含的this指针,因此操作数的个数没有变化,所有的操作数都必须通过函数的形参进行传递,函数的参数与操作数自左至右一一对应。

operator <运算符>(<参数1>,<参数2>)

它等价于

<参数1><运算符><参数2>

例如:a+b等价于operator +(a,b)。
#include <iostream>
#include <cmath>
using namespace std;
class Complex
{
public:
Complex();
Complex(double r);
Complex(double r,double i);
void display();
friend Complex operator+(const Complex &c1,const Complex &c2);
private:
double real;
double imag;
}; Complex::Complex()
{
real=;
imag=;
} Complex::Complex(double r)
{
real=r;
imag=;
} Complex::Complex(double r,double i)
{
real=r;
imag=i;
} Complex operator+(const Complex &c1,const Complex &c2)
{
return Complex(c1.real+c2.real,c1.imag+c2.imag);
} void Complex::display()
{
if(imag>)
cout<<"("<<real<<"+"<<imag<<"i)"<<endl;
else if(imag==)
cout<<"("<<real<<")"<<endl;
else
cout<<"("<<real<<"-"<<fabs(imag)<<"i)"<<endl;
} int main()
{
Complex c1(,),c;
c=c1+2.5;
cout<<"c1+2.5=";
c.display();
return ;
}
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#define max 100
using namespace std; class Matrix
{
public:
Matrix();
friend Matrix operator+(const Matrix &m1,const Matrix &m2);
friend ostream& operator<<(ostream &output,Matrix &m);
void SetValues();
private:
int a[][];
}; Matrix operator+(const Matrix &m1,const Matrix &m2)
{
Matrix m;
for(int i=;i<;i++)
for(int j=;j<;j++)
m.a[i][j]=m1.a[i][j]+m2.a[i][j]; return m;
} Matrix::Matrix()
{
for(int i=;i<;i++)
for(int j=;j<;j++)
{
a[i][j]=;
}
} void Matrix::SetValues()
{
srand((unsigned)time(NULL));
for(int i=;i<;i++)
for(int j=;j<;j++)
a[i][j]=rand()%max;
} ostream& operator<<(ostream &output,Matrix &m)
{
for(int i=;i<;i++)
{
for(int j=;j<;j++)
output<<setw()<<m.a[i][j]<<" "; output<<endl;
}
output<<endl;
return output;
}
int main()
{
Matrix a,b,c;
a.SetValues();
b.SetValues();
c=a+b;
cout<<"a+b="<<endl;
cout<<c<<endl;
return ;
}

(1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。

(2) 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。

(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。

(4) 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。

(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。

(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部类型的对象,该运算符函数必须作为一个友元函数来实现。

(7) 当需要重载运算符具有可交换性时,选择重载为友元函数。

另附一篇重载运算符讲解:https://www.cnblogs.com/zpcdbky/p/5027481.html

c++重在运算符的更多相关文章

  1. c++重在运算符前置自增和后置自增

    class student { int age; }; int main() { class student stu; (stu++)++;//error ++(stu++);//error stu+ ...

  2. C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 对运算符重载的函数有两种处理方式:(1)把运算符 ...

  3. C++ Primer注意事项11_运算符重载_算术/关系运算符_下标运算符

    1.算术/关系运算符 平时,定义成非成员函数以同意左右側运算对象进行转换.由于这些运算符一般不须要改变运算对象的状态,所以形參都是常量的引用. 以"+"号运算符为例: Person ...

  4. RTTI之typeid运算符

    1 #include <iostream> 2 #include <cstdlib> 3 #include <ctime> 4 #include <typei ...

  5. shell运算符

    原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用. expr 是一款表达式计算工具,使用它能完成表达式的求值操作. #!/bin/bash v ...

  6. SQL Server-聚焦APPLY运算符(二十七)

    前言 其实有些新的特性在SQL Server早就已经出现过,但是若非系统的去学习数据库你会发现在实际项目中别人的SQL其实是比较复杂的,其实利用新的SQL Server语法会更加方便和简洁,从本节开始 ...

  7. java中的移位运算符:<<,>>,>>>总结

    java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >& ...

  8. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  9. .NET 基础 一步步 一幕幕[运算符、占位符、转义符]

      运算符.占位符.转义符 好吧,在五局全胜之后,终于升到了三个钻,距离一个星星还有一大段距离,忽然想起来今天的博客还没写,果断坑队友,来写博客了....感觉以后还是每天更新一篇比较好.要不晚上就该熬 ...

随机推荐

  1. ssh原理与应用

    一.什么是SSH? 简单说,SSH是一种网络协议,用于计算机之间的加密登录. 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会 ...

  2. mysql数据库基础知识和认识

    mysql 创建一个用户 hail,密码 hail,指定一个数据库 haildb 给 hail mysql -u root -ppassworduse mysql;insert into user(h ...

  3. C#笔记 -- 协变、逆变

    协变 理解:在泛型和委托中, 让使用某个泛型参数A的类型可以用一个使用由A派生的泛型参数B的类型实例化,(小=> 大)如 ​ // IEnumerable<Animal> 与 Lis ...

  4. fidder设置断点,修改请求参数等

    设置断点(来自:http://jingyan.baidu.com/article/17bd8e52216c8d85ab2bb8e9.html): 可以看到当前有一个抓取的很多的包的链接的地址的信息,那 ...

  5. 第2课:jmeter总结、Charles抓包

    1.  tps(throughput):每秒钟处理的事务数(请求数),定义与qps类似(qps:每秒完成的请求个数.)  响应时间(average):每个请求的平均响应时间 2. jmeter实现下载 ...

  6. C++11_ Lambda

    版权声明:本文为博主原创文章,未经博主允许不得转载. 这次主要介绍C++11的Lambda语法,一个非常给力的语法 1.组成 : [...导入符号](...参数)mutable(可改写)  throw ...

  7. vue.js 源代码学习笔记 ----- instance render

    /* @flow */ import { warn, nextTick, toNumber, _toString, looseEqual, emptyObject, handleError, loos ...

  8. Java对多线程的支持

    Java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在CPU上运行. 在Java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的进程 ...

  9. React-Native进阶_7.TextInput的使用实现搜索功能

    前面使用TabBar 实现了底部tab标签,通过stackNavigator 实现了页面跳转,接下来,使用TextInput 来实现一个搜索功能. TextInput 属性比较多,不一一介绍,具体可以 ...

  10. angular2.0学习日记1

    使用NG2之前需要安装node以及Npm环境,并到node下下载ng2所需要得文件,具体配置请到https://angular.cn/docs/ts/latest/quickstart.html按照提 ...