对运算符重载的方法
对运算符的重载实质是函数的重载
重载运算符的函数一般格式:函数类型 operator 运算符名称(形参表){对运算符的重载处理}
//类声明文件
#include<iostream>
using namespace std;
class Complex
{
public:
Complex(int ,int);
Complex operator + (const Complex &);
private:
int real;
int imag;
};
//类实现文件
#include<iostream>
#include "complex.h"
using namespace std;
Complex::Complex(int r,int i):real(r),imag(i){}
Complex Complex::operator + (const Complex &complex)
{
this->real += complex.real;
this->imag += complex.imag;
return *this;
}
//主函数文件
class Complex complex(12,25);
complex = complex+Complex(15,28);
一般将双目运算符重载为友元函数,所以给出下面的代码
//类声明文件
#include<iostream>
using namespace std;
class Complex
{
public:
Complex();
Complex(int ,int);
friend Complex operator + (const Complex &,const Complex &);
private:
int real;
int imag;
};
//类实现文件
#include<iostream>
#include "complex.h"
using namespace std;
Complex::Complex():real(0),imag(0){}
Complex::Complex(int r,int i):real(r),imag(i){}
Complex operator + (const Complex &complex1,const Complex &complex2)
{
return Complex(complex1.real+complex2.real,complex1.imag+complex2.imag);
}
//主函数文件
class Complex complex;
complex = Complex(15,28)+Complex(15,28);
重载运算符的规则
1、C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载
2、不能重载的运算符有5个: .(成员访问运算符) *(成员指针访问运算符) ::(域运算符)
sizeof(长度运算符) ?:(条件运算符)
必须类内重载的运算符(属于类成员函数,第一个隐形参数是this指针)
=(赋值运算符) [](下标运算符) ()(函数调用) ->(成员访问)
3、重载运算符不能改变运算符运算对象(即操作数)的个数,双目运算符是两个操作数,重载后还是两个操作数
4、重载不能改变运算符的优先级别
5、重载不能改变运算符的结合性
6、重载运算符的函数不能有默认参数
7、重载的运算符必须和用户自定义的类型的对象一起使用,其参数至少应该有一个是类对象(或类对象的引用)
8、用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和“&”必须用户重载
“=”赋值运算符,已经被系统重载过了,除非在指向动态分配内存的指针成员时,否则不需要用户自己在重载
“&”地址运算符,不必重载,返回对象在内存中的起始地址
9、运算符重载后应该尽量表示原有功能不变,(不要把“>”,重载为小于等等)
运算符重载函数作为类成员函数和友元函数
如果运算符重载函数作为类成员函数,则第一个参数(运算符左侧操作数)必须是本类对象,可以通过this指针(第一个隐形的参数)自由访问本类数据,可以少写一个参数;
如果运算符重载中,运算符左侧的操作数不是本类对象,运算符右侧的操作数是本类对象,但是又想访问本类对象的数据成员,这时不能将运算符重载函数作为类成员函数,这时友元函数上线。
C++的一些规则:
1、=(赋值运算符) [](下标运算符) ()(函数调用运算符) ->(成员运算符) 必须作为成员函数
2、一般将单目运算符和复合运算符重载为成员函数
3、流插入<<和流提取运算符>>、类型转换运算符 不能定义为类成员函数,只能作为友元函数
4、一般将双目运算符重载为友元函数
补充一点知识:
C++引入4种类型转换运算符,更加严格的限制允许的类型转换,使转换过程更加规范:
- dynamic_cast 用于多态类型的转换
- static_cast 用于非多态类型的转换
- const_cast 用于删除const ,volatile 和 __unaligned 属性
- reinterpret_cast 用于位的简单重新解释
其中,const_cast和reinterpret_cast的使用会带来更大的风险,因此不到万不得已,不推荐使用
重载双目运算法
双目运算符有两个操作数,一般是友元函数;
//类声明文件
#include<iostream>
using namespace std;
class String
{
public:
String();
String(char *);
friend bool operator > (const String &,const String &);
friend bool operator < (const String &,const String &);
friend bool operator == (const String &,const String &);
friend void compare (const String &,const String &);
void display();
private:
char *ptr;
};
//类实现文件
#include<iostream>
#include "string.h"
String::String():ptr(NULL){};
String::String(char *p):ptr(p){};
void String::display()
{
cout<<ptr;
}
bool operator > (const String &string1,const String &string2)
{
if(strcmp(string1.ptr,string2.ptr)>0) return true;
else return false;
}
bool operator < (const String &string1,const String &string2)
{
if(strcmp(string1.ptr,string2.ptr)<0) return true;
else return false;
}
bool operator == (const String &string1,const String &string2)
{
if(strcmp(string1.ptr,string2.ptr)==0) return true;
else return false;
}
void compare (const String &string1,const String &string2)
{
if((string1 == string2)>0)
{
cout<<string1.ptr;
cout<<"等于";
cout<<string2.ptr;
cout<<endl;
}
if((string1 > string2)>0)
{
cout<<string1.ptr;
cout<<"大于";
cout<<string2.ptr;
cout<<endl;
}
if((string1 < string2)>0)
{
cout<<string1.ptr;
cout<<"小于";
cout<<string2.ptr;
cout<<endl;
}
}
//主函数文件
class String string1("dashaguan");
class String string2("dabendan");
class String string3("dabendan");
compare(string1,string2);
compare(string2,string3);
重载单目运算符
单目运算符只有一个操作数,因此运算符重载函数之后一个参数,如果运算符重载函数作为成员函数,则可省略。
在自增(减)运算符重载函数中,增加一个int型形参(仅仅是为了 区分)就是后置自增(减)运算符函数
//类声明文件
#include<iostream>
using namespace std;
class Time
{
public:
Time();
Time(int ,int );
Time operator ++();
Time operator ++(int);
void display();
private:
int min;
int sec;
};
//类实现文件
#include<iostream>
#include "time.h"
using namespace std;
Time::Time():min(0),sec(0){};
Time::Time(int m,int s):min(m),sec(s){};
Time Time::operator ++()//前++
{
if(++this->sec == 60)
{
++this->min;
this->sec = 0;
}
return *this;
}
Time Time::operator ++(int)//后++
{
Time temp(*this);
if(++this->sec == 60)
{
++this->min;
this->sec = 0;
}
return temp;
}
void Time::display()
{
cout<<this->min<<":"<<this->sec<<endl;
}
//主函数文件
class Time time1(5,59);
time1.display();
++time1;
time1.display();
cout<<"------------------------"<<endl;
class Time time2 = time1++;
time1.display();
time2.display();
重载流插入运算符和流提取运算符
只能将重载“<<”和“>>”函数作为友元函数,而不能将他们定义位成员函数
//类声明函数
#include<iostream>
using namespace std;
class Complex
{
public:
Complex();
Complex(int ,int);
friend Complex operator + (const Complex &,const Complex &);
friend ostream& operator << (ostream&,const Complex &);
friend istream& operator >> (istream&, Complex &);
private:
int real;
int imag;
};
//类实现文件
#include<iostream>
#include<cmath>
#include "complex.h"
using namespace std;
Complex::Complex():real(0),imag(0){}
Complex::Complex(int r,int i):real(r),imag(i){}
Complex operator + (const Complex &complex1,const Complex &complex2)
{
return Complex(complex1.real+complex2.real,complex1.imag+complex2.imag);
}
ostream& operator << (ostream &output,const Complex &complex)
{
cout<<complex.real;
if(complex.imag>0)
cout<<" + "<<complex.imag<<"i";
else
cout<<" - "<<abs(complex.imag)<<"i";
return output;
}
istream& operator >> (istream &input, Complex &complex)
{
cin>>complex.real>>complex.imag;
return input;
}
//主函数文件
class Complex complex1;
complex1 = Complex(15,28)+Complex(15,28);
cout<<complex1<<endl;
class Complex complex2;
cin>>complex2;
cout<<complex2<<endl;
不同类型数据间的转换
1、标准类型数据间的转化
类型名 (数据) e.g. int(17.5)
2、用转换构造函数进行不同类型数据的转换
转换构造函数:将一个其他类型的数据转换成一个类的对象。
e.g. Complex(12.5)
类Complex中全部都是int,但是这时出现了double。首先将double转变为int,然后赋值为real或者imag,与之对应另一个 imag或real赋值为0;下面代码给出的解释(只能出现一个,我只不过是没有注释)
Complex::Complex(double d):real(d),imag(0){};
Complex::Complex(double d):real(0),imag(d){};
注意:转换构造函数只能有一个参数,如果多个参数,就不是转换构造函数
//类声明文件
#include<iostream>
using namespace std;
class Complex
{
public:
Complex();
Complex(double );
Complex(int ,int );
friend Complex operator + (const Complex &,const Complex &);
void display();
private:
int real;
int imag;
};
//类实现文件
#include<iostream>
#include "complex.h"
using namespace std;
Complex::Complex():real(0),imag(0){}
Complex::Complex(double d):real(d),imag(0){};
Complex::Complex(double d):real(0),imag(d){};
Complex::Complex(int r,int i):real(r),imag(i){}
Complex operator + (const Complex &complex1,const Complex &complex2)
{
return Complex(complex1.real+complex2.real,complex1.imag+complex2.imag);
}
void Complex::display()
{
cout<<this->real<<" + "<<this->imag<<"i"<<endl;
}
//主函数文件
class Complex complex;
complex = Complex(15,28)+Complex(15,28);
complex = Complex(15.8,28)+Complex(15.0);
complex.display();
不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成转换构造函数所在的类对象。
例如:将一个学生类对象转换为教师类对象(毕业以后当老师),要求把学生的编号,姓名,性别复制到一个教师类中。
Teacher(Student &s){num = s.num;strcpy(name,s.name);sex = s.sex;}
3、类型转换函数
operator 类型名 () {类型转换语句}
一般会添加const,可以保证对象不被修改,同时也可以得到相应的返回值 operator 类型名 () const {类型转换语句}
在函数名前面不能指定函数类型,函数没有参数。
类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。
当有了相应的转换构造函数情况下,将运算符“+”函数重载为友元函数,在进行两个负数相加时,可以用交换律。
如果将运算符“+”函数重载类成员函数,则交换律不适用。
实例代码(最后三行实现了加法的交换律)
//使用了转换构造函数和运算符“+”重载函数
//类声明文件
#include<iostream>
using namespace std;
class Complex
{
public:
//构造函数
Complex();
//转换构造函数,只有一个形参
Complex(double );
//构造构造函数
Complex(int ,int );
//运算符重载函数
friend Complex operator + (const Complex &,const Complex &);
void display();
private:
int real;
int imag;
};
//类实现文件
#include<iostream>
#include "complex.h"
using namespace std;
Complex::Complex():real(0),imag(0){}
Complex::Complex(double d):real(d),imag(0){};
//Complex::Complex(double d):real(0),imag(d){};
Complex::Complex(int r,int i):real(r),imag(i){}
Complex operator + (const Complex &complex1,const Complex &complex2)
{
return Complex(complex1.real+complex2.real,complex1.imag+complex2.imag);
}
void Complex::display()
{
cout<<this->real<<" + "<<this->imag<<"i"<<endl;
}
//主函数文件
class Complex complex1(3,30),complex3;
complex3 = complex1 + 2.5;
complex3 = 10 + complex1;
//使用了类型转换函数
//类声明文件
#include<iostream>
using namespace std;
class Complex
{
public:
//构造函数
Complex();
//转换构造函数,只有一个形参
//Complex(double );
//构造构造函数
Complex(int ,int );
//运算符重载函数
//friend Complex operator + (const Complex &,const Complex &);
//类型转换函数
operator int();
void display();
private:
int real;
int imag;
};
//类实现文件
#include<iostream>
#include "complex.h"
using namespace std;
Complex::Complex():real(0),imag(0){}
//Complex::Complex(double d):real(d),imag(0){};
//Complex::Complex(double d):real(0),imag(d){};
Complex::Complex(int r,int i):real(r),imag(i){}
/*
Complex operator + (const Complex &complex1,const Complex &complex2)
{
return Complex(complex1.real+complex2.real,complex1.imag+complex2.imag);
}*/
Complex::operator int()
{
return this->real;
}
void Complex::display()
{
cout<<this->real<<" + "<<this->imag<<"i"<<endl;
}
//主函数文件
Complex complex1(5,6);
int b= complex1+5;
cout<<b<<endl;
如果在上述函数中添加了类型转换函数,容易造成二义性。
(转换构造函数和运算符“+”重载函数)与 类型转换函数造成了二义性。
上述的代码中complex3 = 10 + complex1;有两种解释
第一种解释:将10采用转换构造函数变成Complex对象,然后调用运算符“+”重载函数,实现对象的加法
第二种解释:将complex1采用类型转换函数变成int,然后实现整型数据的加法。