目录
C++中的运算符重载允许程序员重新定义已有的运算符,使得这些运算符可以用于自定义的数据类型或对象。
运算符重载作用:
通过运算符重载,程序员可以自定义类的行为,使其在进行运算时像内置类型一样表现
运算符重载的语法格式如下:
返回类型 operator 运算符(参数列表)
{
// 重载的运算符实现
}
返回类型表示运算符重载后的结果类型,operator
是关键字,后面跟着要进行重载的运算符,参数列表包括了运算符操作数
实战讲解
现在有一个A类,A类里中有一个数据成员,创建两个对象,如果两个对象进行运算怎么实现
class A
{
public:
int data;
}
A a1;
A a2;
int end = a1+a2;
解决办法
- 自定义类进行运算
- 编译器编译的时候,会将运算符表达式转换为运算符函数
注意
-
符号的左边作为函数的调用者,右边是函数的参数
能重载的符号
-
双目运算符 +-*/%
-
关系运算符== != < > <= >=
-
逻辑|| && !
-
单目* & ++ --
-
位运算| & ~ ^ << >>
-
赋值= += -=
-
空间申请new delete
-
其他() -> []
不能重载的符号
-
成员访问运算符 .
-
成员指针访问 .*
-
域运算符 ::
-
数据类型长度 sizeof
-
条件 三目 ?:
+
- a1 + a2
a1 + a2 ---> a1.operator+(a2) a1 + a2 ---> operator+(a1,a2) 需要自己在类中定义这个函数,两个函数区别和注意 1.第一个是在类中定义,第二个是在类外定义 2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错 3.两个函数定义其中一个就行 下面是两个函数定义的示例 class A { public: int operator+(int data) { return this->data + data; } int data; }; 如果再在类外定义一个 int operator+(A& a1, A& a2) { return a1.data+ a2.data; } 这个函数,他是不会调用这个函数的,而且可能会报错,
- 10 + a1
10 + a1 ---> operator(10,a1) 需要自己定义这个函数 int operator+(int data, A& a) { return data + a.data; }
- a1 + 10
a1 + 10 ---> a1.operator+(10) a1 + 10 ---> operator+(a1,10) 需要自己在类中定义这个函数,两个函数区别和注意 1.第一个是在类中定义,第二个是在类外定义 2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错 3.两个函数定义其中一个就行 下面是两个函数定义的示例 class A { public: int operator+(int data) { return this->data + data; } int data; }; 如果再在类外定义一个 int operator+(A& a, int data) { return a.data + data; } 这个函数,他是不会调用这个函数的,而且可能会报错,
-
- a1 - 10
a1 - 10 ---> a1.operator-(10) a1 - 10 ---> operator-(a1,10) 需要自己在类中定义这个函数,两个函数区别和注意 1.第一个是在类中定义,第二个是在类外定义 2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错 3.两个函数定义其中一个就行 下面是两个函数定义的示例 class A { public: int operator-(int data) { return this->data - data; } int data; }; 如果再在类外定义一个 int operator-(A& a, int data) { return a.data - data; } 这个函数,他是不会调用这个函数的,而且可能会报错,
- a1 - a2 和 a1 + a2 一样
- 10 - a1 和 10 + a1 一样
>>输入
cin>>a1 ---->operator>>( cin , a1 )
需要自己在类中定义这个函数,两个函数区别和注意
1.第一个是在类中定义,第二个是在类外定义
2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错
3.两个函数定义其中一个就行
下面是两个函数定义的示例
class A
{
public:
istream& operator>>(istream &in, A &a)
{
in >> a.data;
return in;
}
int data;
};
如果再在类外定义一个
istream& operator>>(istream &in, A &a)
{
in >> a.data;
return in;
}
这个函数,他是不会调用这个函数的,而且可能会报错,
<<输出
cout<<a1 ---->operator<<( cout, a1 )
需要自己在类中定义这个函数,两个函数区别和注意
1.第一个是在类中定义,第二个是在类外定义
2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错
3.两个函数定义其中一个就行
下面是两个函数定义的示例
class A
{
public:
ostream& operator<<(ostream &out,A &a)
{
out<<a.data;
return out;
}
int data;
};
如果再在类外定义一个
ostream& operator<<(ostream &out,A &a)
{
out<<a.data;
return out;
}
这个函数,他是不会调用这个函数的,而且可能会报错,
++
- a1++
a1++ ----> a1.operator++(int) a1++ ----> operator++(A的类型,int) int为占位符 需要自己在类中定义这个函数,两个函数区别和注意 1.第一个是在类中定义,第二个是在类外定义 2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错 3.两个函数定义其中一个就行 下面是两个函数定义的示例 class A { public: A(int n=0):data(n){} int operator++(int) { return this->data++; } int data; }; 如果再在类外定义一个 int operator++(A& a,int) { return a.data++; } 这个函数,他是不会调用这个函数的,而且可能会报错,
- ++a1
++a1 ----> a1.operator++() ++a1 ----> operator++(A的类型) int为占位符 需要自己在类中定义这个函数,两个函数区别和注意 1.第一个是在类中定义,第二个是在类外定义 2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错 3.两个函数定义其中一个就行 下面是两个函数定义的示例 class A { public: A(int n=0):data(n){} int operator++() { return ++this->data; } int data; }; 如果再在类外定义一个 int operator++(A& a) { return ++a.data; } 这个函数,他是不会调用这个函数的,而且可能会报错,
--
- a1-- 和 a1++ 一样
- --a1 和 ++a1 一样
==
if( a1 == a2 ) ----> a1.operator==(a2)
if( a1 == a2 ) ----> operator==(a1 , a2)
需要自己在类中定义这个函数,两个函数区别和注意
1.第一个是在类中定义,第二个是在类外定义
2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错
3.两个函数定义其中一个就行
下面是两个函数定义的示例
class A{
public:
A(int n=0):data(n){}
bool operator==(A &ra)
{
return this->data == ra.data;
}
int data;
};
如果再在类外定义一个
bool operator==(A &ra1 , A &ra2)
{
return ra1.data == ra2.data;
}
这个函数,他是不会调用这个函数的,而且可能会报错,
> <
if( a1 > a2 ) ----> a1.operator>(a2)
if( a1 > a2 ) ----> operator>(a1 , a2)
if( a1 < a2 ) ----> a1.operator<(a2)
if( a1 < a2 ) ----> operator<(a1 , a2)
需要自己在类中定义这个函数,两个函数区别和注意
1.第一个是在类中定义,第二个是在类外定义
2.如果两个函数都定义,他会默认调用类中定义的函数,也有可能出错
3.两个函数定义其中一个就行
4.大于和小于函数都一样,改一下函数就好
下面是两个函数定义的示例
class A{
public:
A(int n=0):data(n){}
bool operator>(A &ra)
{
return this->data > ra.data;
}
int data;
};
如果再在类外定义一个
bool operator>(A &ra1 , A &ra2)
{
return ra1.data > ra2.data;
}
这个函数,他是不会调用这个函数的,而且可能会报错,
+= -=
类内的重载函数和全局函数定义其中一个就好
class Vector {
public:
double x, y;
Vector(double x, double y) : x(x), y(y) {}
// 重载+=运算符,实现增量相加
Vector& operator+=(const Vector& v) {
this->x += v.x;
this->y += v.y;
return *this;
}
// 重载-=运算符,实现增量减法
Vector& operator-=(const Vector& v) {
this->x -= v.x;
this->y -= v.y;
return *this;
}
void display() {
std::cout << "Vector: (" << x << ", " << y << ")" << std::endl;
}
};
// 全局重载+=运算符
Vector operator+=(const Vector& v1, const Vector& v2) {
return Vector(v1.x + v2.x, v1.y + v2.y);
}
// 全局重载-=运算符
Vector operator-=(const Vector& v1, const Vector& v2) {
return Vector(v1.x - v2.x, v1.y - v2.y);
}
Vector v1(1.0, 2.0);
Vector v2(3.0, 4.0);
v1 += v2; //调用重载的+=运算符v1 += v2与v1 = Vector(v1.x + v2.x, v1.y + v2.y)的作用是相同的
v1.display(); //输出 (4.0, 6.0)
v1 -= v2; //调用重载的-=运算符
v1.display(); //输出 (1.0, 2.0)
()
A(200) 转成员函数重载-->A.operator()(int)
#include <iostream>
using namespace std;
class Data
{
public:
Data(int n=0):data(n),flag(true){}
void show(){cout<<data<<endl;}
int operator()()
{
return this->data;
}//小括号运算符int ret = m1();
int operator()(const int &a)
{
return (this->data +a);
}//小括号运算符int ret = m1(300);
private:
int data;
bool flag;
};
int main()
{
Data m1(10);
int ret = m1();//int operator()()小括号运算符
int ret = m1(300);//int operator()(const int &a)大括号运算符
cout<<ret::<<ret<<endl;
return 0;
}
A(200) 转非成员函数--->operator()()(A的类型,int)
int operator()(const Data& v1 , const int &a)
{
return (v1.data + a);
}
[]
A[200] 转非成员函数-->operator[]()(A的类型,int)
A[2] 转成员函数重载-->A.operator[](int)
#include <iostream>
using namespace std;
class Array
{
public:
Array(int size)
{
this->m_arr = new int[size];
memset(this->m_arr,0,size);
this->m_size = size;
}
~Array()
{
delete []this->m_arr;
}
int operator[](int index)
{
return this->m_arr[index];
}//大括号运算符
private:
int *m_arr;
int m_size;
};
int main()
{
Array a(100);
cout<<a[2]<<endl;//会转化为a[2]--->a.operator[](2)大括号运算符
return 0;
}
如果想实现a[2] = 100;
可以返回引用,return this->m_arr[index];
也可以返回 return &
~ !
类内成员函数
!m1 -----> m1.operator!()
~m1 -----> m1.operator~()
class Data{
public:
Data(int n=0):data(n),flag(true){}
void show(){cout<<data<<endl;}
Data operator+(const Data &a){
Data temp(0);
temp.data = this->data + a.data;
return temp;
}
bool operator!(){
return !(this->flag);
}//类成员函数重载,!m1 cout<<!A:<<!m1<<endl;
int operator~(){
return ~(this->flag);
}//类成员函数重载,~m1 cout<<~A<<~m1<<endl;
private:
int data;
bool flag;
};
int main(){
Data m1(0x10);
Data m2(20);
cout<<!A:<<!m1<<endl;
cout<<~A<<~m1<<endl;
return 0;
}
全局函数
!m1 -----> operator!(const Data& a)
~m1 -----> operator~(const Data& a)
class Data {
public:
Data(int n = 0) : data(n), flag(true) {}
void show() { std::cout << data << std::endl; }
int getData() const { return data; }
bool getFlag() const { return flag; }
private:
int data;
bool flag;
};
// 重载逻辑非操作符
bool operator!(const Data& a) {
return !(a.getFlag());
}
// 重载按位取反操作符
int operator~(const Data& a) {
return ~(a.getFlag());
}
int main()
{
Data m1(0x10);
std::cout << "!m1: " << !m1 << std::endl;
std::cout << "~m1: " << ~m1 << std::endl;
return 0;
}
注意:
- 如果想在全局重载函数中调用类的私有函数,要将全局函数定义为友元函数
总结
- 重载运算符限制在C++语言中已有的运算符范围内,并且允许重载的运算符之中,不能创建新的运算符。
- 运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。
- 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
- 运算符重载不能改变该运算符用于内部类型对象的含义。它只能和用户自定义类型的对象一起使用,或者用于用户自定义类型的对象和内部类型的对象混合使用时。
- 运算符重载是针对新类型数据的实际需要对原有运算符进行的适当的改造,重载的功能应当与原有功能相类似,避免没有目的地使用重载运算符。