运算符重载

前面做题的时候发现c++逆向的题目里面对于运算符重载的考察率还是很高的,所以单独学一下

1.概述

1.概念

用同一个运算符完成不同的运算

2.规定

  1. 不能改变运算符的优先级
  2. 不能改变运算符的结合性
  3. 默认参数不能和重载的运算符一起使用,也就是说,在设计运算符重载成员函数时不能使用默认函数
  4. 不能改变运算符的操作数的个数
  5. 不能创建新的运算符,只有已有运算符可以被重载
  6. 运算符作用于C++内部提供的数据类型时,原来含义保持不变

可被重载的运算符

在这里插入图片描述

不可被重载的运算符

  1. .(点运算符)通常用于去对象的成员,但是->(箭头运算符),是可以重载的
  2. ::(域运算符)即类名+域运算符,取成员,不可以重载
  3. (点星运算符,)不可以重载,成员指针运算符”.,即成员是指针类型
  4. ?:(条件运算符)不可以重载
  5. sizeof不可以重载

3.定义格式

运算符重载函数作为类的成员函数

函数类型    operator    重载运算符(形参表)
{
函数体;
}

运算符重载函数作为类的友元函数

friend  函数类型    operator    重载运算符(形参表)
{
函数体;
}
  1. “函数类型”指出重载运算符的返回值类型
  2. operator是定义运算符重载函数的关键词
  3. “重载运算符”指出要重载的运算符名字,是C++中可重载的运算符,比如要重载加法运算符
  4. 这里直接写“+”即可,“形参表”指出重载运算符所需要的参数及其类型

2.重载单目运算符

1.重载“++”和“–”运算符

“++”和“–”重载运算符也有前缀和后缀两种运算符重载形式

以“++”重载运算符为例

语法格式

函数类型        operater        ++()
函数类型        operater        ++(int)

实际示例

#include<iostream>
using namespace std;
class MyClass2
{
int n; // 私有成员变量
public:
MyClass2(int i){ n = i; } // 构造函数

// 前置递增运算符重载
int operator ++(){
n++;       // 增加 n 的值
return n;   // 返回递增后的值
}

// 后置递增运算符重载
// int 参数是一个特殊参数,用来区分前置和后置递增
int operator ++(int){
n += 2;     // 将 n 增加 2
return n;   // 返回增加后的值
}

// 方法展示当前 MyClass2 对象的 n 值
void display()
{
cout << "n=" << n << endl;
}
};
  1. int operator ++() 是前置递增运算符的重载在调用时,它会先将对象的私有成员 n 增加1,然后返回递增后的值。
  2. int operator ++(int) 是后置递增运算符的重载。在调用时,它会将对象的私有成员 n 增加2,并返回递增后的值。这里的 int 参数并未被使用但是它区分了这是后置运算符而不是前置运算符

这里有两种运算符的使用方法

A++; // 调用后置递增,n 会增加 2,A.n 变为 7
++B; // 调用前置递增,n 会增加 1,B.n 变为 6

2.重载->运算符

“->”运算符是成员访问运算符,这种单目运算符只能被重载为成员函数

一般成员访问运算符的格式

对象->成员

成员访问运算符“->”函数重载的一般形式

数据类型        类名::operator->();

实验示例

class PClass
{
int n; double m; // 私有成员变量,一个整数和一个双精度浮点数

public:
PClass *operator->()
{
return this; // 返回当前对象的 this 指针
}

void setvalue(int n1, double m1)
{
n = n1; m = m1; // 设置 n 和 m 的值
}

void disp()
{
// 打印对象的 n 和 m 成员
cout << "n=" << n << ",m=" << m << endl;
}
};

结果:

在这里插入图片描述

上述程序中,重载“->”运算符的成员函数,该函数返回当前对象的指针

从而导致“s->disp();”和“s.disp();”两个语句都是正确的,实际上,前者通过调用重载“->”运算符成员函数转换成后者的格式

使用方法

PClass *operator->():该函数重载了箭头运算符 ->

通常情况下,这个运算符应当在处理指向类对象的指针时被使用

但在这段代码中,它返回 PClass 对象本身的 this 指针

使得可以在 PClass 对象上通过 -> 符号调用其成员函数

PClass s;        // 创建一个 PClass 对象
s->setvalue(10, 20.5); // 使用重载的 -> 运算符,实际上等同于 s.setvalue(10, 20.5);
s->disp(); // 同样使用重载的 -> 运算符,等同于 s.disp();
s.setvalue(20, 89.8); // 直接调用 setvalue 函数,无需重载的 -> 运算符
s.disp(); // 直接调用 disp 函数

注释:

1.setvalue

PClass 类中定义的一个成员函数,它用来设置类的两个私有成员变量 nm 的值

成员 n 是一个 int 类型,而 m 是一个 double 类型

这个函数接收两个参数:

一个 int 类型的 n1 和一个 double 类型的 m1,并将这两个参数的值分别赋给类的成员变量 nm

具体实现:

void setvalue(int n1, double m1)
{
n = n1; // 将传入的整型参数 n1 赋值给类成员 n
m = m1; // 将传入的双精度浮点型参数 m1 赋值给类成员 m
}
2.disp

PClass 类的成员函数,它用来显示或打印该类的私有成员变量 nm 的当前值

disp 函数没有参数,它通过访问对象的私有成员直接打印它们的值。

void disp()
{
// 打印输出 n 和 m 的值
cout << "n=" << n << ",m=" << m << endl;
}

函数使用 cout 来输出信息,这是C++标准库中的一个对象,允许你在控制台上打印信息

<< 是插入运算符,用于将所提供的数据插入到输出流中

在这个例子中,它将 nm 的值转换为文本并打印出来

endl 是操纵器,用于向输出流插入一个换行符,并刷新输出缓冲区,这意味着它会使得在它之前的所有输出都立即显示在控制台上。

1.当调用 disp 函数时,假设 n 的值为 10m 的值为 20.5,输出将是:
n=10,m=20.5

在给定的代码上下文中,如果有一个 PClass 实例 s

调用 s.disp(); 将会打印出 s 的成员变量 nm 的值

2.如果先前有过如 s.setvalue(20, 89.8); 这样的调用,s.disp(); 的输出将会是:
n=20,m=89.8

重载双目运算符

重载双目运算符为成员函数

假设有一个类A,对于双目运算符op

如果重载运算符op使之能够实现表达式“obj1 op obj2”,其中obj1和obj2均为A类的对象

若把op重载为A类的成员函数:

该函数只有一个形参,形参的类型是obj2所属的类型。经过重载之后,表达式“obj1 op obj2”解释为:

obj1.operator	op(obj2)

左边的Obj1通过this指针传递,右边的对象obj2由参数传递

重载双目运算符为友元函数

假设有一个类A,对于双目运算符op

如果重载运算符op使之能够实现表达式“obj1 op obj2”,其中obj1和obj2均为A类的对象。 若把op重载为A类的友元函数:

该函数有两个形参,经过重载之后,表达式“obj1 op obj2”解释为

obj1	op(obj1,obj2)

左右两个对象obj1,obj2都由参数传递

下面是重载运算符为成员函数和重载为友元函数的对比

重载运算符为成员函数

#include<iostream>
using namespace std;

class vector {
int x, y;
public:
vector() {} //默认构造函数
vector(int x1, int y1) { //重载构造函数
x = x1; y = y1;
}

// 下面的成员函数重载 + 和 - 运算符
/*
vector operator+(vector v) {
vector tmp;
tmp.x = x + v.x;
tmp.y = y + v.y;
return tmp;
}

vector operator-(vector v) {
vector tmp;
tmp.x = x - v.x;
tmp.y = y - v.y;
return tmp;
}
*/

void display() {
cout << "(" << x << "," << y << ")";
}
};

int main() { // 注意这里应该是 int main() 而不是 void main()
vector v1(2, 3), v2(3, 5), v3, v4;
cout << "v1:"; v1.display();
cout << "v2:"; v2.display();

// 由于 + 和 - 运算符被注释掉,下面两行代码将无法编译
// v3 = v1 + v2;
// v4 = v1 - v2;

cout << "v3:"; v3.display();
cout << "v4:"; v4.display();

system("pause"); // 这行在某些系统或编译器中是不必要的或不起作用的
return 0; // main 函数结束时返回 0
}

重载运算符为友元函数:

#include<iostream>
using namespace std;

class vector {
int x, y;
public:
vector(){}; //默认构造函数
vector(int x1, int y1) { //重载构造函数
x = x1; y = y1;
}

// 以下是+和-运算符的重载实现,声明为友元函数
friend vector operator+(vector v, vector v1) {
vector tmp;
tmp.x = v1.x + v.x;
tmp.y = v1.y + v.y;
return tmp;
}

friend vector operator-(vector v, vector v1) {
vector tmp;
tmp.x = v1.x - v.x;
tmp.y = v1.y - v.y;
return tmp;
}

void display() {
cout << "(" << x << "," << y << ")";
}
};

int main() {
vector v1(2, 3), v2(3, 5), v3, v4;
cout << "v1:"; v1.display();
cout << "v2:"; v2.display();
v3 = v1 + v2; v4 = v1 - v2;
cout << "\nv3:"; v3.display();
cout << "\nv4:"; v4.display();
system("pause"); // 注意,这是特定于Windows平台的命令
return 0; // main 函数通过返回 0 表示正常退出
}

注:重载运算符为成员函数和友元函数时关键的区别在于成员函数具有this指针,而友元函数没有this指针

重载比较运算符

比较运算符函数重载必须返回true(非0)和false(0)

#include<iostream>
#include<cmath>
using namespace std;

class vector {
int x, y;
public:
vector() : x(0), y(0) {}

vector(int x1, int y1) : x(x1), y(y1) {}

// 计算向量的长度(即从原点到向量点的距离)
double length() const {
return sqrt(x * x + y * y);
}

// 重载小于比较运算符
bool operator<(const vector& rhs) const {
return this->length() < rhs.length();
}

void display() const {
cout << "(" << x << ", " << y << ")";
}
};

int main() {
vector v1(2, 3), v2(3, 4);
cout << "v1: "; v1.display();
cout << "\nv2: "; v2.display();
cout << "\nIs v1 smaller than v2? " << (v1 < v2 ? "Yes" : "No") << endl;

return 0;
}

v1v2vector类的两个对象

重载的<运算符比较v1v2的长度。length函数计算每个向量的长度(即从原点到该点的距离),然后比较运算符<基于这个长度来返回truefalse

operator<返回true如果左侧向量(即this指向的对象)的长度小于右侧向量(即rhs参数指向的对象)的长度,否则返回false。在main函数中,v1 < v2的结果将被用来在控制台上输出比较的结果

重载赋值运算符

重载“+=”和“-=”运算符

#include<iostream>
using namespace std;
class vector
{
int x, y; // 私有成员变量,表示向量的x和y坐标
public:
vector(){} // 默认构造函数
vector(int x1, int y1) // 带参数的构造函数
{
x = x1; y = y1; // 初始化向量的x和y坐标
}
// operator+=重载实现,友元函数,意味着它可以访问类的私有成员
friend vector operator+=(vector v1, vector v2)
{
vector tmp; // 创建一个新的向量对象来存储结果
tmp.x = v1.x + v2.x; // 两个向量的x坐标相加
tmp.y = v1.y + v2.y; // 两个向量的y坐标相加
return tmp; //返回新的向量对象
}
// operator-=重载实现,成员函数
vector operator-=(vector v)
{
vector tmp; // 创建一个新的向量对象来存储结果
tmp.x = x - v.x; // 当前向量的x坐标减去参数向量的x坐标
tmp.y = y - v.y; // 当前向量的y坐标减去参数向量的y坐标
return tmp; //返回新的向量对象
}
// 用于输出向量坐标的辅助函数
void display(){ cout << "(" << x << "," << y << ")"<<endl; }
};

int main()
{
vector v1(3, 2), v2(6, 5), v3, v4;
v1.display();
v2.display();
v3 = v1 += v2;
v4 = v2 -= v1;
// 显示结果
v3.display();
v4.display();
v1.display();
v2.display();
system("pause"); // 暂停,以便观察结果,仅适用于Windows
}

一点自己的的理解:

他这地方是指在v3=v1+=v2时按照常规的运算规则v1应该被重新赋值然后再赋值给v3,但是重载之后就不会改变v1地址存储的的数据,但是依旧可以赋值给v3

重载=运算符

赋值运算符=的原有含义是将赋值号右边表达式的结果复制给赋值号左边的变量,通过运算符=的重载将赋值号右边的数据成员函数依次复制给左边对象的数据成员中

重载下标运算符

下标运算符“[ ]”通常用于获取数组的某个元素,重载下标运算符可以实现数组下标的越界检测等。下标运算符重载只能作为类的成员函数,不能作为类的友元函数

//设置一个Assoc类,其中用一个数组表示每个单词的情况,而且每个单词除了他出现的次数,
//还应保存该单词本身,因此定义一个结构。该类中有一个重载运算符“[ ]”成员函数,用来返回
//某个单词已经出现的次数,返回值是一个引用,可用于改变值。在每查找到一种单词后返回以出
//现的次数在运算符后边进行++运算,相对于返回值++,间接地起到每找到一个单词便将它的出现次数
//+1的目的。
#include<iostream>
#include<string.h>
using namespace std;
struct Pair//说明结构体类型
{
char *name;//单词
int num;//出现的次数
};
class Assoc
{
struct Pair *vec;//指向结构体变量的指针
int size;//分配总的单元个数
int used;//已使用的单元个数
public:
Assoc(int m)//构造函数
{
size = (m > 16) ? m : 16;//size至少大于16
used = 0;
vec = new Pair[size];//分配空间
}
int & operator [] (char *);
void disp();
};
int & Assoc::operator[](char *p)//返回的是pp->num的引用
{
struct Pair *pp;
for (pp = vec; pp < vec + used; pp++)//在已有的单词中查找
if (strcmp(p, pp->name) == 0)//若找到返回次数
return pp->num;
pp = &vec[used++];//在已有的单词中未找到,则使用的单元个数+1
pp->name = new char[strlen(p) + 1];//分配一个单元空间
strcpy(pp->name, p);
pp->num = 0;
return pp->num;//返回0
}
void Assoc::disp()
{
cout << "单词出现次数统计:" << endl;
for (int i = 0; i < used; i++)
{
cout << " " << vec[i].name << ":" << vec[i].num << "次" << endl;
}
}
void main()
{
char buf[16];
Assoc vecc(20);//设置20个单元存放单词
int k = 10;
cout << "请输入" << k << "个单词" << endl;
for (int i = 0; i < k; i++)
{
cout << "第" << i + 1 << "个单词:";
cin >> buf;
vecc[buf]++;//调用“[]”,并将该单词出现次数增1
}
vecc.disp();
system("pause");
}
image-20240725170954367

重载new和delete运算符

new和delete只能被重载为类的成员函数,不能重载为友元

而且,无论是否使用关键字static进行修饰,重载了的new和delete均为类的静态成员函数

void	*类名::operator	new(size_t,参数表);

在带有“参数表”时,应注意使用重载new的方式

若有一个类X有如下重载new的成员函数:

void* operator new(size_t size,int x,int y,int z)
{……
}

使用重载new的方式如下

x*pX=new(1,2,3) X;

运算符delete重载的格式一般如下

void *类名“::operator delete(void*,参数表);

重载类型转换运算符

重载类型转换运算符格式

operator 类型名()
{
函数体;
}
  1. 类型转换运算符没有返回类型,因为类型名就代表了它的返回类型,而且没有任何参数
  2. 转换运算符重载的缺点是无法定义其类对象运算符操作的真正含义,因为只能进行相应的对象成员数据和一般数据变量的转换操作

重载函数调用运算符

函数调用运算符“()”只能说明成类的非静态成员函数

一般格式

函数类型 类名::operator()(参数表)

与普通函数一样,重载了的函数调用运算符可以事先带有零个或多个参数

#include<iostream>
using namespace std;

class PClass {
public:
// 重载的函数调用运算符,接受两个 double 类型的参数 x 和 y,并返回一个 double 类型的值
double operator()(double x, double y) const;

// 重载的函数调用运算符,接受一个 double 类型的参数 x,并返回一个 double 类型的值
double operator()(double x) const;
};

// 重载的函数调用运算符的定义,接受两个 double 类型的参数 x 和 y,并返回一个 double 类型的值
double PClass::operator()(double x, double y) const {
// 比较 x 和 y,返回较大的值
if (x < y)
return y;
else
return x;
}

// 重载的函数调用运算符的定义,接受一个 double 类型的参数 x,并返回一个 double 类型的值
double PClass::operator()(double x) const {
// 如果 x 小于 0,则返回其绝对值,否则返回 x
if (x < 0)
return (-x);
else
return x;
}

int main() {
// 创建 PClass 类的对象 fun
PClass fun;

// 通过对象 fun 调用重载的函数调用运算符,传入两个参数,并输出结果
cout << fun(1.2, 2.3) << endl;

// 通过对象 fun 调用重载的函数调用运算符,传入一个参数,并输出结果
cout << fun(-6) << endl;

// 暂停程序,等待用户输入任意键后结束
system("pause");

// 返回 0,表示程序成功结束
return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇