C++运算符重载总结(真的很详细了w(?Д?)w)
概述
运算符重载可以使得一些特殊类型参与运算,我是这样理解的。
使用友元形式的运算符重载
//一般形式
class x{
friend 返回类型 operator 运算符(形参表);
};
返回类型 operator 运算符(形参表)
{}
双目运算符
所以加减乘除就可以这样来进行声明了
返回类型 operator +(-、*、/) (形参表);
单目运算符
如- & ! ++(前),++(后)
等。下面以++(后)
来进行一个示例:
class code{
int x, y;
};
code operator++(code& op, int)//第二个参数仅仅表示这个++是后缀加
{
code tmp(op);
x++;
y++;
return tmp;//返回增加之前的状态,这样也对后加加有了进一步理解了。
}
总结:
- 运算符重载可以返回任何类型,甚至是
void
类型,但是通常都是返回和操作数相同的类型。 - 下面运算符只能使用成员函数运算符重载,不能使用友元函数来重载。
运算符名称 =
等号 []
下标运算符 ()
函数调用运算符 ->
指针成员运算符 - 对于同一个运算符,可以写多个函数来进行重载。
使用成员运算符进行重载
//一般形式
class x{
返回类型 operator 运算符(参数表);
}
返回类型 x::operator 运算符(参数表)
{
具体实现
}
双目运算符重载
这里需要注意的是:参数表中的个数会少一个,因为左操作数是隐含在this
中的。
但是类内的静态函数没有this
指针。
例如:
class code{
int x, y;
public:
code(int a, int b):x(a), y(b){}
code operator+(code p){
return code(x+p.x, y+p.y);
}
};
code A(1, 2), B(3, 4);
code C=A+B;//这时C.x=4, C.y=6;
单目运算符重载
形式和上面差不多,这里不再赘述。
运算符重载需要注意的几个问题
c++
语言只能对已经有的c++
运算符进行重载,不允许用户自己定义新的运算符。- 绝大多数运算符都能重载,但是有例外,下面五个不能进行重载:
名称 .
成员访问运算符 .*
成员指针访问运算符 ::
作用域运算符 sizeof
长度运算符 ?:
条件运算符 - 重载的功能应当和原有的功能类似
- 重载不能改变运算符的操作对象
- 重载不能改变运算符原有的优先级
- 重载不能改变运算符原有的结合特性
- 重载参数应该至少有一个是类对象,不能都是
c++
预定义的类型(要不然就没有意义了) - 双目运算符一般两种重载形式都可以,但是有的时候只能用友元形式来进行重载。例如:
AB::operator+(int x){ return AB(a+x, b+x); } ob1=ob2+100; //这里这样调用是可以的,编译器理解为ob1=ob2.operator(100); //但是下面的情况就会出现问题 ob1=100+ob2; //等价于ob1=100.operator(ob2);但是100不是一个对象
如果我们定义下面两个友元函数就会很好的解决这个问题
friend AB operator+(AB ob, int x); friend AB operator+(int x, AB ob); //这样ob1=100+ob2; ob1=ob2+100;都没有问题 //这里我们也可以整合,使用类型转换函数,将int类型转换为对象类型,对象类型转换为int类型,不过真没啥意思
几个常见的运算符重载
等号“ = ”
运算符重载,只能使用成员函数进行重载
这里我们重载=
主要是进行深拷贝操作(当然这里也可以自己写一个拷贝构造函数来进行)。
在重载等号运算符重载时要注意自己等于自己的情况
mystring& mystring::operator=(mystring &s)
{
if(this==&s)return *this;//防止出现s=s的赋值;
if(p!=NULL)
delete []p;
p=new char[strlen(s.p)+1];
strcpy(p, s.p);
return *this;
}
下标运算符重载[]
,
只能使用成员函数进行重载,要注意这是个双目运算符, x[y],x是左操作符,y是右操作符
**
返回类型 类名::operator[] (参数表){
函数体
}
//有时返回类型可以使用引用类型,只要不是返回的变量不是在函数内声明的临时变量就可以
class AB{
int num[10];
int len;
int& operator[](int);
}
int& AB::operator[](int b)
{
if(b<0 || b>=10)
return -1;
else return num[b]; //这里num[b]不是一个临时变量,而是存在于对象中。
}
函数调用运算符重载()
只能使用成员函数进行重载
注意这里()
看被作双目运算符的,x(y), x是左操作数,y是右操作数
//给出坐标,返回二维矩阵的某个元素的值.
class matrix{
int *m;//用一维的数组来进行模拟
int row, col; //行数,列数
}
int& matrix::operator()(int r, int c){
return *(m+r*col+c);
}
m(3, 5)//这里解释为m.operator()(3, 5);
()
运算符是唯一一个可带多个右操作数的运算符函数
输出运算符和输入运算符的重载
<<
运算符的重载
定义原型:需要注意成员函数形式和友元函数形式的区别,他们调用方式不相同
//成员函数类型,注意如果使用下面的类型,那么调用的方式是:对象名<<cout;
ostream& operator<<(ostream& out){
out<<x<<" "<<y<<endl;
return out;
}
ob<<cout;//相当于ob.operator<<(cout);
//因为上面这种形式有点反直觉,所以很少用,所以大部分都是采用友元形式
//友元函数类型
friend ostream& operator<<(ostream& out, 自定义类名& 对象名){
//out可以改为别的名
out<<对象.x<<对象.y<<endl;
return out;
}
cout<<ob; //使用这种形式来进行输出
对于<<
的参数详解,《C++ Primer中文版:第五版》
\(494\)页是这样解释的:
输出运算符的第一个形参是一个非常量的
ostream
对象的引用。之所以ostream
是非常量是因为向流写入内容会改变其状态;而该形参是因为我们无法复制一个ostream
对象。第二个形参一般来说是一个常量的引用,该常量是我们想要打印的类类型。第二个形参是引用的原因是我们希望避免赋值实参;而之所以该形参可以是常量是因为(通常情况下)打印对象不会改变对象的内容。
为了与其他输出运算符保持一致,
operator<<
一般要返回它的ostream
形参。
>>
输入运算符重载
这里的基本规则和上面重载输出运算符差不多,需要多注意的是,输入过程中要考虑到输入可能失败的情况。
原文地址:https://www.cnblogs.com/alking1001/p/12003178.html