什么是运算符重载
重载我们分析过了,就是对一个已有的函数,使其参数的个数,类型不同来赋予新的含义,实现新的功能。那么运算符也可以被重载赋予新的含义和功能。这就运算符重载。
为什么会用运算符重载机制
我们在开发中都使用过运算符,一般情况下我们接触最多的就是加减乘除,还有new,delete这些运算法,直接使用他们只能对单一类型的数据进行操作。例如我们想对自定义类型进行运算操作时,该怎么办呢?重载运算符就显得极其重要了。
#pragma warning(disable : 4996)
#include <iostream>
using namespace std;
class Complex
{
friend Complex Add(Complex &c1, Complex &c2);
friend Complex operator+(Complex &c1, Complex &c2);
public:
Complex(int a, int b)
{
this->m_a = a;
this->m_b = b;
}
//成员函数(在类的内部完成两个数据的和)
int GetAdd()
{
return m_a + m_b;
}
//成员函数(在类的内部完成两个类的数据的和)
Complex GetAdd(Complex &c1)
{
Complex temp = Complex(this->m_a + c1.m_a, this->m_b + c1.m_b);
return temp;
}
private:
int m_a, m_b;
};
//全局函数(要访问类的私有成员可以使用友元friend)
Complex Add(Complex &c1,Complex &c2)
{
Complex temp = Complex(c1.m_a + c2.m_a, c1.m_b + c2.m_b);
return temp;
}
//重载“+”运算法
Complex operator+(Complex &c1, Complex &c2)
{
Complex temp = Complex(c1.m_a + c2.m_a, c1.m_b + c2.m_b);
return temp;
}
int main()
{
//使用成员函数
Complex c1(1, 2), c2(3, 4);
int a1 = c1.GetAdd();
int a2 = c2.GetAdd();
int a3 = a1 + a2;
cout << "c1与c2的和 = " << a3 << endl;
//使用成员函数
Complex c3 = c1.GetAdd(c2);
int a4 = c3.GetAdd();
cout << "c1与c2的和 = " << a4 << endl;
//使用友元函数
Complex c4 = Add(c1, c2);
int a5 = c4.GetAdd();
cout << "c1与c2的和 = " << a5 << endl;
//使用"operator+"重载运算符
Complex c5 = c1 + c2;
int a6 = c5.GetAdd();
cout << "c1与c2的和 = " << a5 << endl;
system("pause");
return 0;
}
看上面的例子,如果我们想对同一类型的两个对象的数据成员进行加法运算时,可以用很多种方式达到其目的,有成员函数,友元函数,同样可以重载运算符达到其目的。
Complex c5 = c1 + c2
原因Complex是用户自定义类型,编译器根本不知道如何进行相加。可是编译器给我们提供了一种机制,让我们自己去完成自定义类型的相加操作,而这一机制就是运算符重载机制。
运算符重载的限制
可以重载的运算符
+ - * / % ^ & | ~
! = < > += -= *= /= %=
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- ->* ‘ ->
[] () new delete new[] delete[]
不能重载的运算符
. :: .* ?: sizeof
重载运算符函数可以对运算符做出新的解释,但原有基本语义不变
- 不改变运算符的优先级
- 不改变运算符的结合性
- 不改变运算符所需的操作数
- 不能创建新的运算符
运算符重载规则
运算符函数是一种特殊的成员函数或友元函数(运算符重载的本质是一个函数)
类型 类名 :: operator op(参数表){}
返回值 关键字 函数名(操作数)
全局函数、类成员函数方法实现运算符重载步骤
- 要承认操作符重载是一个函数,写出函数名称operator op ()
- 根据操作数,写出函数参数
- 根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务
运算符重载的两种方法
用成员或友元函数重载
- 运算符函数可以重载为成员函数或友元函数
- 关键区别在于成员函数具有this指针,友元函数没有this指针
- 不管使用成员函数或友元函数重载运算符,其使用方法相同,但传递参数的方式不同,实现代码不同,应用场合不同
例:字符串类的封装以及业务实现
// MyString.h
#pragma once
#include <iostream>
using namespace std;
#pragma warning(disable : 4996)
class MyString
{
friend ostream & operator<<(ostream &out, MyString &s);
friend istream & operator>>(istream &input, MyString &s);
public:
MyString(const char *s );
MyString(int len = 0);
MyString(const MyString &obj);
void MyPrint();
~MyString();
public:
MyString & operator=(const MyString &obj);
MyString & operator=(const char *s);
char &operator[](int index)const;
public:
bool operator==(const char *str)const;
bool operator!=( const char *str)const;
bool operator==(const MyString &s)const;
bool operator!=(const MyString &s)const;
/*bool operator<(const char *str)const;
bool operator>(const char *str)const;
bool operator<(const MyString &s)const;
bool operator>(const MyString &s)const;*/
public:
char * Str();
const char *c_Str();
int Length();
private:
char *str;
int m_len;
};
//MyString.cpp
#include "MyString.h"
MyString::MyString(const char *s)
{
if (s == NULL)
{
this->m_len = 0;
this->str = new char[m_len + 1];
strcpy(str, "");
}
else
{
this->m_len = strlen(s);
cout << m_len << endl;
this->str = new char[m_len + 1];
strcpy(str, s);
}
}
MyString::MyString(int len)
{
if (len == 0)
{
this->m_len = 0;
this->str = new char[m_len + 1];
strcpy(str, "");
}
else
{
this->m_len = len;
this->str = new char[m_len + 1];
memset(this->str, 0, m_len);
}
}
MyString::MyString(const MyString & obj)
{
this->m_len = obj.m_len;
this->str = new char[m_len + 1];
strcpy(str, obj.str);
}
void MyString::MyPrint()
{
cout << str << endl;
}
MyString::~MyString()
{
if (this->str != NULL)
delete[] str;
this->m_len = 0;
}
MyString & MyString::operator=(const MyString &obj)
{
if (this->str != NULL)
{
delete[] str;
m_len = 0;
}
this->m_len = obj.m_len;
this->str = new char[m_len+1];
strcpy(str, obj.str);
return *this;
}
MyString& MyString::operator=( const char *s)
{
if (this->str != NULL)
{
delete[] str;
m_len = 0;
}
if (s == NULL)
{
m_len = 0;
str = new char[m_len + 1];
strcpy(str, "");
}
else
{
m_len = strlen(s);
str = new char[m_len + 1];
strcpy(str, s);
}
return *this;
}
char & MyString::operator[](int index) const
{
return str[index];
}
bool MyString::operator==(const char * str)const
{
if (str == NULL)
{
if (this->m_len == 0)
return true;
else
return false;
}
else
{
if (this->m_len == strlen(str))
{
return !strcmp(this->str, str);
}
else
{
return false;
}
}
}
bool MyString::operator!=(const char * str)const
{
return !(*this == str);
}
bool MyString::operator==(const MyString & s)const
{
if (m_len != s.m_len)
return false;
else
{
return !strcmp(this->str, s.str);
}
}
bool MyString::operator!=(const MyString & s)const
{
return !(*this == s);
}
char * MyString::Str()
{
return this->str;
}
const char * MyString::c_Str()
{
return this->str;
}
int MyString::Length()
{
return this->m_len;
}
//bool MyString::operator<(const char * str) const
//{
// return strcmp(this->str, str );
//}
//
//bool MyString::operator>(const char * str) const
//{
// return strcmp(str, this->str);
//}
//
//bool MyString::operator<(const MyString & s) const
//{
// return strcmp(this->str, s.str);
//}
//
//bool MyString::operator>(const MyString & s) const
//{
// return strcmp(s.str, this->str);
//}
ostream & operator<<(ostream & out, MyString & s)
{
return out << s.str;
}
istream & operator>>(istream & input, MyString & s)
{
return input >> s.str;
}
总结
1、对于自定义类型进行运算时,我们会使用到运算符重载
2、成员函数和友元函数都可以重载运算符,其参数,代码实现,应用场景不同
3、运算符的重载符合运算符的优先级,结合性,操作数。