运算符重载的两种方式
1 基本概念
基础
-
运算符时具有特殊名字的函数:由关键字operator和气候定义的运算符共同组成。
-
可以被重载的运算符
方式
- 将运算符重载为类的成员函数。
- 重载运算符函数,并声明为类的友元。
规则
-
重载后的运算符必须至少有一个操作数是用户定义的类型,这是为了防止程序员为标准类型重载运算符,可以确保程序正确运行。
-
不能修改运算符的优先级,不能违反运算符原本的运算规则。例如在重载加号时,不能提供两个形参(友元除外),例如下面的这种重载方式就是不被允许的;因为加法是一种双目运算符。在重载为类的成员函数后,加法运算的第一项应该是调用函数的一个对象。所以在运算符重载时,参数表中的参数数目应该是重载运算符的操作数减1。
Time operator+(const Time &t1,const Time &t2) const;
- 不能创造新的运算符,例如不能定义operator**()运算符;
- 不能重载以下运算符;
.:成员运算符
.*:成员指针运算符
:: :作用域运算符
?::条件运算符
siezof:sizeof运算符。
- 很多运算符可以通过成员或者非成员函数进行重载,但是以下四种只能通过成员函数进行重载;
=:赋值运算符;
( ):函数调用运算符;
[ ]: 下标运算符
->:通过指针方位类成员的运算符。
- 自增运算符(++)与自减运算符(–)由于自增和自减运算符是单目运算符,在重载时应该是没有参数的,但是又有前置与后置之分,例如++i与i++。为了隽星区分,C++做了规定;
Time operator++() //前置
Time operator++(int) //后置
2 成员函数重载
成员函数重载格式
- 将操作符重载为成员函数。
- 此时类的对象作为操作符的第一个操作数。流输入输出运算符无法通过这样的方式重载,因为对象本身应该作为第二个操作数,只能通过友元函数的方式对操作进行重载。
class MyString{
public:
// 重载等号运算符
MyString& operator=(const MyString &b);
// 重载+=运算符
MyString& operator+=(const MyString &b);
}
3 友元重载
友元的格式
C++中友元有三种,分别是友元函数,友元类,友元成员函数,这里介绍的是友元函数。
- 创建友元函数的第一步是声明,友元函数的声明放在类的声明中,并且在前面加上friend关键字。例如;
friend ostream& operator<<(ostream &os, const Time &t);
- 第二步是定义友元,友元可以直接在声明的时候进行定义,即内联的定义。也可以定义在类外,定义在类外时,不需要加类作用域运算符,也不需要有friend关键字。
//友元在类外定义的时候,不需要添加friend;
ostream & operator<<(ostream &os, const Time &t)
{
os << "hours:" << t.hours << " " << "mintues:" << t.mintues << " ";
return os;
}
友元使用
与普通的运算符重载成员函数一样,友元也可以直接调用
cout<<time1<<time2;//等价于
operator<<(operator<<(cout,time1),time2);
4 实例——MyString的实现
/*
* C++ string 类的实现
* 1. 构造函数和析构函数
* 2. 字符串长度
* 3. 重载=运算符
* 4. 重载+=运算符
* 5. 重载<< >> 运算符
* 6. 重载比较运算符
* 7. 重载[]下标运算符
*/
#include <iostream>
#include <cstring>
using namespace std;
class MyString
{
private:
char * str;
int length;
public:
// 长度
int size ()const {
return length;
};
char* getstr()const{
return str;
}
// 默认构造函数
MyString();
// 字符串构造函数
MyString(const char*);
// 复制构造函数
MyString(const MyString& b);
// 重载等号运算符
MyString& operator=(const MyString &b);
// 重载+=运算符
MyString& operator+=(const MyString &b);
// 重载比较运算符
bool operator<(const MyString &b);
// 重载下标运算符
char& operator[](const int &index) const ;
// 重载输入输出操作
friend ostream& operator<<(ostream& ,const MyString &b);
~MyString();
};
MyString::MyString()
{
str = new char[1];
str[0]='\0';
length = 0;
}
MyString::MyString(const char* b){
if(b){
length = strlen(b);
str = new char[length+1];
strcpy(str,b);
}
else{
MyString();
}
}
MyString::MyString(const MyString&b){
length = b.size();
if(length>0)
str = new char[length+1];
else
MyString();
}
MyString& MyString::operator=(const MyString &b){
if(&b == this){
return *this;
}
delete[] str;
length = b.size();
str = new char[length + 1];
strcpy(str,b.getstr());
return *this;
}
MyString& MyString::operator+=(const MyString&b){
if(b.size()==0){
return *this;
}
char* temp = new char[length+b.length+1];
strcpy(temp,str);
strcat(temp,b.getstr());
delete[] str;
str = temp;
return *this;
}
char& MyString::operator[](const int &index)const {
if(index>length)return str[length];
return str[index];
}
bool MyString::operator<(const MyString &b){
for(int i=0;i<length;i++){
if(i>b.size())return false;
if(b[i]>str[i])return true;
if(b[i]<str[i])return false;
}
return true;
}
MyString::~MyString()
{
delete[] str;
}
// 外部定义一个函数,内部声明为友元
ostream& operator<<(ostream &out,const MyString&b){
out<<b.getstr();
return out;
}
int main()
{
// 测试函数
MyString s1,s2="123",s3,s4="456";
s3=s2;
s1=s2;
s1+=s1;
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;
cout<<(s3<s4)<<endl;
cout<<endl;
return 0;
}
5 实例——complex的实现
#include <iostream>
using namespace std;
class complex{
public:
complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ };
public:
friend complex operator+(const complex & A, const complex & B);
friend complex operator-(const complex & A, const complex & B);
friend complex operator*(const complex & A, const complex & B);
friend complex operator/(const complex & A, const complex & B);
friend istream & operator>>(istream & in, complex & A);
friend ostream & operator<<(ostream & out, complex & A);
private:
double m_real; //实部
double m_imag; //虚部
};
//重载加法运算符
complex operator+(const complex & A, const complex &B){
complex C;
C.m_real = A.m_real + B.m_real;
C.m_imag = A.m_imag + B.m_imag;
return C;
}
//重载减法运算符
complex operator-(const complex & A, const complex &B){
complex C;
C.m_real = A.m_real - B.m_real;
C.m_imag = A.m_imag - B.m_imag;
return C;
}
//重载乘法运算符
complex operator*(const complex & A, const complex &B){
complex C;
C.m_real = A.m_real * B.m_real - A.m_imag * B.m_imag;
C.m_imag = A.m_imag * B.m_real + A.m_real * B.m_imag;
return C;
}
//重载除法运算符
complex operator/(const complex & A, const complex & B){
complex C;
double square = A.m_real * A.m_real + A.m_imag * A.m_imag;
C.m_real = (A.m_real * B.m_real + A.m_imag * B.m_imag)/square;
C.m_imag = (A.m_imag * B.m_real - A.m_real * B.m_imag)/square;
return C;
}
//重载输入运算符
istream & operator>>(istream & in, complex & A){
in >> A.m_real >> A.m_imag;
return in;
}
//重载输出运算符
ostream & operator<<(ostream & out, complex & A){
out << A.m_real <<" + "<< A.m_imag <<" i ";;
return out;
}
int main(){
complex c1, c2, c3;
cin>>c1>>c2;
c3 = c1 + c2;
cout<<"c1 + c2 = "<<c3<<endl;
c3 = c1 - c2;
cout<<"c1 - c2 = "<<c3<<endl;
c3 = c1 * c2;
cout<<"c1 * c2 = "<<c3<<endl;
c3 = c1 / c2;
cout<<"c1 / c2 = "<<c3<<endl;
return 0;
}
6 实例——MyTime的实现
//------mytime.h
#ifndef MYTIME_H
#define MYTIME_H
#include <iostream>
using namespace std;
class Time
{
//----------私有成员,类中的成员默认是私有的
private:
int hours;
int mintues;
//----------共有成员
public:
Time(); //默认构造函数
Time(int h, int m = 0); //显式构造函数
Time(const Time &); //拷贝构造函数
~Time(); //析构函数
void AddMin(int m);
void AddHour(int h);
void reset(int h = 0, int m = 0);
//------展示函数show()
void Time::show() const
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " ";
}
Time operator+(const Time &t) const; //运算符重载
Time operator-(const Time &t) const;
Time operator*(double n) const;
friend Time operator*(double n, const Time &t) //友元;
{
return t*n; //在这里又调用了重载运算符 operator*(double n) const;
} //内联形式的定义;
friend ostream & operator<<(ostream &os, const Time &t); //一个双目运算符在重载时,如果是以友元的形式声明的,那么他有两个形参;如果是类的成员函数,那么他只有一个形参;
};
//-------时间重置,内联函数
inline void Time::reset(int h, int m)
{
hours = h;
mintues = m;
}
#endif
//--mytime.cpp
#include <iostream>
#include "mytime.h"
using namespace std;
//-------默认构造函数
Time::Time()
{
hours = mintues = 0;
cout << "调用默认构造函数" << endl;
}
//------显式的构造函数
Time::Time(int h, int m) :hours(h), mintues(m)
{
cout << "调用显式构造函数" << endl;
}
//------拷贝构造函数
Time::Time(const Time &t)
{
hours = t.hours;
mintues = t.mintues;
cout << "调用拷贝构造函数" << endl;
}
//------析构函数
Time::~Time()
{
cout << "调用了析构函数" << endl;
}
//-------小时相加
void Time::AddHour(int h)
{
hours += h;
}
//------分钟相加
void Time::AddMin(int m)
{
mintues += m;
hours += mintues / 60;
mintues %= 60;
}
//------重载+号
Time Time::operator+(const Time &t) const
{
Time sum;
sum.mintues = mintues + t.mintues;
sum.hours = hours + t.hours + sum.mintues / 60;
sum.mintues = sum.mintues % 60;
return sum;
}
//------重载-号
Time Time::operator-(const Time &t) const
{
Time diff;
int time1 = hours * 60 + mintues;
int time2 = t.hours * 60 + t.mintues;
diff.hours = (time1 - time2) / 60;
diff.mintues = (time1 - time2) % 60;
return diff;
}
//-------重载乘号
Time Time::operator*(double n) const
{
Time result;
long totalMintues = n*hours * 60 + n*mintues;
result.hours = totalMintues / 60;
result.mintues = totalMintues % 60;
return result;
}
//-------友元输出操作符
ostream & operator<<(ostream &os, const Time &t) //友元在类外定义的时候,不需要添加friend;
{
os << "hours:" << t.hours << " " << "mintues:" << t.mintues << " ";
return os;
}
//-----------------------
//main.cpp
//不用先生
//------------------------
#include <iostream>
#include "mytime.h"
using namespace std;
int main()
{
{
Time eat_breakfast(0, 45);
Time eat_lunch(1, 0);
Time eat_dinner(1, 30);
Time swiming(0, 45); //非const对象,既可以调用const成员函数,也可以调用非const成员。
const Time study(8, 5); //const对象只能调用const成员函数。
// study_cut_swim;
Time study_cut_swim = study - swiming; //调用运算符重载后的Time类的减号;
Time Eat_time_day = eat_breakfast + eat_dinner + eat_lunch; //调用了重载以后的加法;
cout << "学习比游泳多花" << study_cut_swim << endl; //调用友元输出运算符<<
cout << "每周吃饭所花费的时间为" << (7 * Eat_time_day) << endl; //调用了友元乘法以及输出运算符;
}
system("pause");
return 0;
}