运算符重载
心得体会:如果不做特殊处理,C++的“+”“-”“*”“/”等等的运算符只能用于最基本的数的运算,而不能用于对象间的运算。如果可以将对象也进行这类操作,程序会更加的简洁,易懂。比如对两个复数对象进行计算。通过运算符的重载,赋予运算符新的功能,就能解决这类对象之间运算的问题。
运算符重载的概念和原理
可以重载的运算符
+ - * / % ^ & | ~
! = < > += -= *= /= %
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- ->* ‘ ->
[] () new delete new[] delete[]
不能重载的算符
. :: .* ?: sizeof
重载运算符函数可以对运算符做出新的解释,但运算符重载后,原有的基本语义不变,包括:
(1)不改变运算符的优先级
(2)不改变运算符的结合性
(3)不改变运算符所需要的操作数
(4)不能创建新的运算符
一元运算符:
Object op 或 op Object
当重载为成员函数时,解释为:Object . operator op ()
操作数由对象Object通过this指针隐含传递
当重载为友元函数时,解释为:Operator op (Object)
操作数由参数表的参数Object提供
二元运算符:
Object op ObjectR
当重载为成员函数,解释为:
ObjectL operator op (ObjectR)
左操作数由ObjectL通过this指针传递,由操作数由函数ObjectR传递
当重载为友元函数,解释为:
operator op (ObjectL , ObjectR)
左右操作数都由参数传递
1. 运算符函数可以重载为成员函数或友元函数
①用成员函数重载运算符:
成员运算符函数的原型在类的内部声明格式如下:
class X {
//…
返回类型 operator运算符(形参表);
//…
}
在类外定义成员运算符函数的格式如下:
返回类型 X::operator运算符(形参表)
{
函数体
}
#include <bits/stdc++.h>
using namespace std;
class Complex
{
public:
double real;
double imag;
Complex( ){
real=0,imag=0;
}
Complex(double r,double i){
real=r;
imag=i;
}
Complex operator + (Complex &c2);
void display( );
};
Complex Complex:: operator + (Complex &c2) {
return Complex(real+c2.real, imag+c2.imag);
}
void Complex::display( ){
cout<<"("<<real<<","<<imag<<"i)"<<endl;
}
int main( ){
Complex c1(3,4),c2(5,-10),c3;
c3=c1+c2;
cout<<"c1=";
c1.display( );
cout<<"c2=";
c2.display( );
cout<<"c1+c2 =";
c3.display( );
return 0;
}
②用友元函数重载运算符:
友元函数重载运算符常用于运算符的左右操作数类型不同的情况
#include<bits/stdc++.h>
using namespace std;
class Complex
{
double Real,Image ;
public:
Complex( double r =0, double i =0 ) {
Real = r;
Image = i;
}
Complex(int a) {
Real = a;
Image = 0;
}
void print()const ;
friend Complex operator + ( const Complex & c1, const Complex & c2 ) ;
friend Complex operator - ( const Complex & c1, const Complex & c2 ) ;
friend Complex operator - ( const Complex & c ) ;
};
Complex operator + ( const Complex & c1, const Complex & c2 ){
double r = c1.Real + c2.Real ; double i = c1.Image+c2.Image ;
return Complex ( r, i ) ;
}
Complex operator - ( const Complex & c1, const Complex & c2 ){
double r = c1.Real - c2.Real ; double i = c1.Image - c2.Image ;
return Complex ( r, i ) ;
}
Complex operator - ( const Complex & c ){
return Complex ( -c.Real, - c.Image );
}
void Complex :: print() const{
cout << '(' << Real << " , " << Image << ')' << endl;
}
int main()
{
}
几个典型运算符重载
1.重载赋值运算符“=”
赋值运算符重载用于对象数据的复制
operator=必须重载为成员函数
赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的。有时希望“=”两边的操作数的类型即使不兼容也能够成立,这就需要对“=”进行重载
#include<bits/stdc++.h>
using namespace std;
class String
{
char* str;
public:
String():str(NULL){}//将stl初始化为NULL仅当执行了operator成员函数后,str才会指向动态分配的存储空间,并且从此后其值不可能再为NULL
const char* c_str()const{return str;};//函数返回了指向String对象内部动态分配的存储空间的指针,但是不希望外部的到这个指针后修改其指向的字符串的内容,因此将返回类型设为const char*
String & operator = (const char* s);
~String();
};
String&String::operator = (const char* s)
{
if(str)//在String对象的生存期内,有可能从未执行过operator=成员函数,所以在析构函数中,执行delete【】str之前要先判断str是否为NULL
delete [] str;
if(s){
str=new char[strlen(s)+1];
strcpy(str,s);
}
else
str=NULL;
return* this;
}
String::~String()
{
if(str)//在operator=函数中,要先判断str是否已经指向动态分配的存储空间,如果是,要先释放那片空间,然后重新分配一片空间,再将参数s指向的内容复制过去,这样,对象中存放的字符串就和s指向的字符串一样了
delete [] str;
}
int main()
{
String s;
s="Good Morning,";
cout<<s.c_str()<<endl;
s="Mr.Shen";
cout<<s.c_str()<<endl;
return 0;
}
//如果没有对=进行重载,s="Good morning,"肯定会因为两边类型不匹配而编译出错
一般地,返回值是被赋值者的引用,即*this,原因是
①这样在函数返回时避免一次拷贝,提高了效率。
②更重要的,这样可以实现连续赋值,即类似a=b=c这样。如果不是返回引用而是返回值类型,那么,执行a=b时,调用赋值运算符重载函数,在函数返回时,由于返回的是值类型,所以要对return后边的“东西”进行一次拷贝,得到一个未命名的副本,然后将这个副本返回,而这个副本是右值,所以,执行a=b后,得到的是一个右值,再执行=c就会出错。
2.重载自增、自减运算符
成员函数重载++:
#include<iostream>
using namespace std;
class Increase
{ public :
Increase ( ) {value=0;}
void display( )const{cout<<value<<'\n';};
Increase operator ++ ( ) ; // 前置
Increase operator ++ (int) ; // 后置
private:
unsigned value ;
};
Increase Increase :: operator ++ ( ){
value ++;
return *this;
}
Increase Increase :: operator ++(int){
Increase temp;
temp.value = value ++;
return temp;
}
int main( )
{
Increase a,b,n;
int i ;
for (i=0 ;i<10;i++) a=n++;
cout <<"n= ";
n.display( );
cout <<"a= ";
a.display( );
for (i=0;i<10;i++)b=++n;
cout<<"n=";
n.display( );
cout <<"b= ";
b.display( ) ;
}
友元函数重载++:
#include<iostream>
using namespace std;
class Increase
{ public :
Increase(){value=0;}
void display()const{cout<<value<<'\n';};
friend Increase operator ++(Increase &);// 前置
friend Increase operator ++(Increase &,int);// 后置
private:
unsigned value;
};
Increase operator ++(Increase &a)
{
a.value ++;
return a;
}
Increase operator ++(Increase &a,int)
{
Increase temp(a);
a.value ++;
return temp;
}
int main( )
{
Increase a,b,n;
int i;
for (i=0;i<10;i++)
a=n++;
cout<<"n= ";
n.display();
cout<<"a= ";
a.display();
for(i=0;i<10;i++)
b=++n;
cout<<"n= ";
n.display();
cout<<"b=";
b.display();
}
3.重载流插入和流提取运算符
定义输出运算符“<<”重载函数的一般格式如下:
ostream& operator<<(ostream& out,class_name&obj)
{
out<<obj.item1;
out<<obj.item2;
.. .
out<<obj.itemn;
return out;
}
重载输入运算符“>>” (只能被重载成友元函数)
定义输入运算符函数 “>>”重载函数的一般格式如下:
istream& operator>>(istream& in,class_name&obj)
{
in>>obj.item1;
in>>obj.item2;
. . .
in>>obj.itemn;
return in;
}
#include <iostream>
using namespace std;
class Point
{
int x,y;
public:
friend istream & operator>>(istream & in, Point &p);
friend ostream & operator<<(ostream & out,const Point &p);
};
istream & operator>>(istream & in, Point &p)
{
cout<<"Please input apoint:"<<endl;
in>>p.x;
in>>p.y;
return in;
}
ostream &operator<<(ostream & out,const Point &p)
{
out<<"("<<p.x<< ","<<p.y <<")"<<endl;
return out;
}
int main()
{
Point p;
cin>>p;
cout<<p;
return 0;
}
上一篇: Grpc Golang 客户端调用 Java 服务端
下一篇: 运算符重载