C++基础 学习笔记五:重载之运算符重载

时间:2024-01-17 16:30:50

C++基础 学习笔记五:重载之运算符重载

什么是运算符重载

用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载。运算符重载是静态多态性的体现。

运算符重载的规则

  1. 重载公式

返回值类型 operator 运算符名称 (形参表列){}

  1. 能够重载的运算符

    + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , ->* -> () [] new new[] delete delete[]

  2. 不能重载的运算符

    sizeof: ?.::

  3. 重载不能改变运算符的优先级和结合性

  4. 重载不会改变运算符的用法

  5. 运算符重载函数不能有默认的参数

  6. 重载后的运算符必须至少有一个操作数是用户自定义的类型,以此来防止为标准类型重载运算符。

  7. 特殊的运算符

    ->[ ]( )=只能以成员函数的形式重载

运算符重载的实现原理

以运算符作为名称的函数称之为运算符函数。这种重载称为运算符重载。

具体实现(以运算符+ -为例)

1. 在全局范围内重载运算符

Complex operator+(const Complex &leftArg, const Complex &rightArg)
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
Complex sum = leftArg + rightArg;

第五行调用函数operator+,并且将leftArgleftArg作为符号函数的参数,返回值赋值给sum,等同于sum = operator+(leftArg,rightArg);

2.在类中重载运算符

class Complex
{
public:
Complex operator-(const Complex & arg)
{
return Complex(this.real - arg.real, this.imag - arg.imag);
}
};
Complex diff = leftArg - rightArg;

第九行调用函数operator-,并且将leftArg作为符号函数的参数,返回值赋值给diff,等同于diff = leftArg.operator-(rightArg);

运算符重载的使用例子

#include<iostream>
#include<string> using namespace std; enum complePart
{
real = 0,
imag
}; class Complex
{
public:
int real;
int imag;
public:
Complex() : real(0),imag(0){}
Complex(int r, int i) : real(r),imag(i){}
Complex operator-(const Complex & arg)// +,-,*,/ 这四个运算符重载方法一样
{
return Complex(this->real - arg.real, imag - arg.imag);
}
friend Complex operator*(const Complex &leftArg, const Complex &rightArg);//友元函数
bool operator==(const Complex &arg)// ==,!= 这两个个运算符重载方法一样
{
if(this->real == arg.real && this->imag == arg.imag)
return true;
else
return false;
}
Complex& operator+=(const Complex &arg)// +=,-=,*=,/= 这四个运算符重载方法一样
{
this->real += arg.real;
this->imag += arg.imag;
return *this;
}
friend istream& operator>>(istream &input, Complex &complex);
friend ostream& operator<<(ostream &output, Complex &complex);
Complex& operator++()// ++i,--i 这两个个运算符重载方法一样
{
++this->real;
++this->imag;
return *this;
}
Complex operator++(int i)// i++,i-- 这两个个运算符重载方法一样
{
Complex tempComplex = *this;
++this->real;
++this->imag;
return tempComplex;
}
void* operator new(size_t size)
{
cout << "call function void* operator new(size_t size)" << endl;
void* pointer = malloc(size);
return pointer;
}
void operator delete(void* pointer)
{
cout << "call function void operator delete(void* pointer)" << endl;
free(pointer);
}
void* operator new[](size_t size)
{
cout << "call function void* operator new[](size_t size)" << endl;
void* pointer = malloc(size);
return pointer;
}
void operator delete[](void* pointer)
{
cout << "call function void operator delete[](void* pointer)" << endl;
free(pointer);
}
void* operator new(size_t size,Complex* complex,int step)//placement new
{
cout << "call function void* operator new(size_t size,Complex* complex,int step)" << endl;
return complex + step;
}
operator int()
{
return this->real;
}//c->operator int()
int& operator [](int i)
{
int errorValue = 0;
if(i == 0)
return this->real;
else//为了演示不要在意
return this->imag;
}
const int& operator[](int i) const
{
cout << "call function const int& operator[](int i) const" << endl;
if(i == 0)
return this->real;
else//为了演示不要在意
return this->imag;
}
}; Complex operator+(const Complex &leftArg, const Complex &rightArg)//全局重载
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
istream& operator>>(istream &input, Complex &complex)
{
input >> complex.real >> complex.imag;
return input;
}
ostream& operator<<(ostream &output, Complex &complex)
{
output << complex.real << " " << complex.imag << " ";
return output;
}
Complex operator*(const Complex &leftArg, const Complex &rightArg)
{
return Complex((leftArg.real * rightArg.real) - (leftArg.imag * rightArg.imag),
(leftArg.imag * rightArg.real) - (leftArg.real * rightArg.imag));
} int main()
{
Complex leftArg(2,2);
Complex rightArg;
cin >> rightArg;//输入3,3
Complex result = leftArg + rightArg;
cout << result << endl;
result = leftArg - rightArg;
cout << result << endl;
result = leftArg * rightArg;
cout << result << endl;
string str = (leftArg == rightArg)?"true":"false";
cout << str << endl;
result += leftArg;
cout << result << endl;
cout << ++result << endl;
Complex resulttttt = result++;
cout << resulttttt << endl;
cout << result << endl;
Complex* pointer = new Complex(1,1);
cout << *pointer << endl;
delete pointer;
Complex* pointerArray = new Complex[10];
cout << pointerArray[2] << endl;
new(pointerArray, 2)Complex(123,321);//placement new
cout << pointerArray[2] << endl;
cout << (int)pointerArray[2] << endl;
cout << pointerArray[2][complePart::real] << endl;
cout << pointerArray[2][complePart::imag] << endl;
delete[] pointerArray;
const Complex c_result(111,222);
cout << c_result[complePart::imag] << endl; return 0;
}
/* 运行结果为:
3 3
5 5
-1 -1
0 0
false
2 2
3 3
3 3
4 4
call function void* operator new(size_t size)
1 1
call function void operator delete(void* pointer)
call function void* operator new[](size_t size)
0 0
call function void* operator new(size_t size,Complex* complex,int step)
123 321
123
123
321
call function void operator delete[](void* pointer)
call function const int& operator[](int i) const
222 --------------------------------
Process exited after 3.063 seconds with return value 0
请按任意键继续. . .
*/

代码分析

1.双目运算符

+-*/%这五个运算符均为双目运算符,重载方法相同。重载例子详见第20、24、102、116行,其中第102行的+重载函数为全局重载,测试详见第127、129、131行。

2.关系运算符

==!=<><=>=这六个运算符均为关系运算符,重载方法相同。重载例子详见第25行,测试详见第133行。

3.自增自减运算符

++--这两个运算符均为自增自减运算符,由于运算符的特殊性,运算符又分为前置和后置形式。重载方法两种形式不同,但是相同形式的重载方法相同。重载例子详见第40、46行,测试详见第137、138行。

4.空间申请与释放运算符

newdeletenew[]delete[]这四个运算符均为空间申请与释放运算符,重载方法相似。重载例子详见第53、59、64、70行,测试详见第141、143、144、151行。在重载空间申请运算符时除newnew[]这两种方式外还有一种方式叫做placement new。重载例子详见第75行,测试详见第146行。

placement new

通常new操作分两步:

  1. 分配内存。
  2. 若为类则调用类的构造函数创建对象。

但是若已分配好内存如:Complex* pointerArray = new Complex[10];,若要在pointerArray[2]分配的内存上创建对象则需要用placement new来完成该操作。操作如下:new(pointerArray, 2)Complex(123,321);,完成该操作后pointerArray[2]中的复数对象将会变为123+321i

5.输入和输出运算符

>><<这两个运算符均为输入和输出运算符,重载方法相似。可以将输出运算符<<和输入运算符>>看作是C++对左移运算符<<和右移运算符>>分别进行了重载,但只能输出输入标准类型。重载例子详见第38、39行,测试详见第126、128行。

6.其它运算符

  1. (数据类型)运算符

    (数据类型)是强制类型转换运算符,可以将对象转换为相应的类型。

  2. []运算符

    []是下标运算符,可以将对象转换为类似数组,可以通过下标操纵对象。

重载运算符的形式

1.以成员函数重载运算符

成员函数重载只允许右参数的隐式转换,一般单目运算符以成员函数重载。只能重载为成员函数的运算符:=()[]->等。

2.以全局函数(友元函数)重载运算符

友元函数重载能够接受左参数和右参数的隐式转换,友员函数重载运算符常用于运算符的左右操作数类型不同的情况。一般双目运算符以友元函数重载。只能重载为友元函数的运算符:<<>>等。