【C++】 重载操作符

news/2024/10/18 7:45:17/

目录

概念

类内重载操作符

类外重载操作符

使用注意

对象类型转换

封装Iterator


概念

  C++提供的运算符,通常只支持对于基本数据类型和标准库中提供的类进行操作,对于自定义类型如果想通过操作符实现对应的操作,需要自定义重载的操作符并实现具体的功能。

  C++编译器,当遇到该运算符时就调用此函数来行使运算符功能,本质是通过函数扩展了操作符的功能。重载操作符函数需要使用关键字operator作为函数名的一部分,重载操作符一般要有返回值,方便继续和其他操作符去操作。

可分两类:类内重载、类外重载

类内重载操作符

  在类内重载,作为类成员函数,需要用对象调用,使用场景需要根据函数的参数一致(包括类型和顺序),注意在类内重载的操作符函数有隐藏的this指针作为第一个参数。

  在使用时要注意重载操作符的参数类型和顺序,可以直接使用操作符,也可以显示通过对象调用重载的操作符。

class CTest {
public:int m_a;CTest (/*int m_a*/) :m_a(1) {//this->m_a = m_a;}int add(int a) {return this->m_a + a;}//函数名 operator加上要重载的符号,参数要与操作符的使用规则和使用场景一致(参数的顺序,类型匹配),//返回类型一般是要存在的,目的是为了和后续的操作符继续去操作,int operator+(/*CTest * const this*/int a) {return this->m_a + a;}int operator+=(int a) {return m_a += a;}};
int main() {CTest tst;//tst + 2;  //tst.m_a + 2cout << tst.add(2) << endl;cout << tst + 2 << endl;//2 + tst;  //不能匹配 int operator+(/*CTest * const this*/int a)int b = tst + 2;  //可以承接返回类型cout << tst.operator+(3) << endl;//通过对象显示调用这个重载操作符函数tst += 4;cout << tst.m_a << endl;return 0;
}

对于单目运算符++,有左++和右++两种,为了区分右++,我们需要额外指定一个int类型的参数,这个参数只是用来区分,并无实际意义。

class CTest{//左++int operator++() {return ++this->m_a;}//右++int operator++(int) {return this->m_a++;}
};

类外重载操作符

  在类外重载操作符时,至少需要包含一个自定义类型,在类内的重载操作符函数有默认的this且为自定义类型,所以定义函数时忽略了第一个参数,但类外重载没有隐藏的参数了,一般比类内要多一个参数。但要注意是否与类内重载的函数有冲突。

int operator+(int a, CTest& tst) {return a + tst.m_a;
}int operator+(CTest& tst,int a) {return a + tst.m_a;
}int operator*(CTest& tst) {return tst.m_a;
}//左++
int operator++(CTest & tst) {return ++tst.m_a;
}//右++
int operator++(CTest& tst,int) {return tst.m_a++;
}

如果类内类外产生歧义,调用不明确,可以用显示的方式来调用,但是不推荐。

	cout << 2 + tst << endl; //3//cout << tst + 3<< endl;  //4cout << tst.operator+(4) << endl;//5

自定义重载输入输出操作符,一般在类外重载。

ostream& operator<<(ostream& os, CTest& tst) {os << tst.m_a;return os;
}istream& operator>>(istream& is, CTest& tst) {is >> tst.m_a;return is;
}

使用注意

对于同一个操作符来说,写在不同的位置代表不同的含义,*p和a*b,那么重载这个操作符需要注意参数的数量、顺序不同代表不同的含义。

//类内重载
int operator*();      //间接引用
int operator*(int);   //乘法

注意:

  1. 不能重载的运算符:长度运算符 sizeof、三目运算符 ? :、成员选择符 . 、作用域运算符 :: 等。
  2. 还有一些操作符只能在类内重载,赋值=,下标[],调用(),成员指向->,操作符必须被定义为类成员操作符。
  3. 重载操作符不能改变操作符的用法,原来有几个操作数、操作数在左边还是右边,这些都不会改变。
  4. 运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。
  5. 重载操作符不能改变运算符的优先级和结合性
  6. 不能创建新的运算符。

对象类型转换

上面重载等号操作符operator=,能让其他的类型赋值到当前类对象中,但是如果反过来写则会报错,类型不匹配,因为operator=只能在类内重载。

此时可以重载某个类型,这样定义该类对象就可以像这个类型一样去使用。

函数格式为:

operator type(){return type_value;  //类型要和type一致
}

函数在写法上无参数,无返回值,但函数体中应该有return,且return的变量类型要和重载的类型一致。

operator int(){int a = 10;return a;
}

我们通常会将指针类型转换为bool类型用以判断

class CTest {
public:char* m_p;CTest() :m_p(new char[] {"123"}) {}~CTest() {if (m_p) delete []m_p;m_p = nullptr;}operator bool() {return m_p;}};
void fun(CTest& tst) {if (tst) cout << tst.m_p << endl;
}

如果同时存在重载操作符和重载类型,那么优先匹配重载的操作符

int a = tst + 10;  //operator+
a = 10 + tst;      //operator int
a = tst;           //operator int

当然也可以显示的调用 类型转换函数

int a = tst.operator int() + 10;  //operator int

封装Iterator

在学过重载操作符后,我们可以封装链表的迭代器,包含临时指针和对应的操作。

class CIterator {
private:Node* m_pNode;
public:CIterator():m_pNode(nullptr){}CIterator(Node* pNode) :m_pNode(pNode) {}Node* operator=(Node* pNode) {m_pNode = pNode;return m_pNode;}bool operator!=(Node* pNode) {return m_pNode != pNode;}bool operator==(Node* pNode) {return m_pNode == pNode;}operator bool() {return m_pNode;}int operator*() {return m_pNode->val;}//左++Node* operator++() {m_pNode = m_pNode->pNext;return m_pNode;}Node* operator++(int) {Node* pTemp = m_pNode;  //先标记一下m_pNode = m_pNode->pNext;  //后去移动return pTemp;}};

使用迭代器遍历链表

	void ShowList() {//迭代器CIterator ite(m_pHead);    while (ite != nullptr) { cout << *ite << "   ";++ite;}cout << endl;}

http://www.ppmy.cn/news/59335.html

相关文章

Android中Paint字体的灵活使用

在Android开发中&#xff0c;Paint是一个非常重要的绘图工具&#xff0c;可以用于在控制台应用程序或Java GUI应用程序中绘制各种形状和图案。其中&#xff0c;Paint.setText()方法是用于设置Paint绘制的文本内容的。在Android开发中&#xff0c;如果你想要设置文本内容&#x…

红黑树理论详解与Java实现

文章目录 基本定义五大性质红黑树和2-3-4树的关系红黑树和2-3-4树各结点对应关系添加结点到红黑树注意事项添加的所有情况 添加导致不平衡叔父节点不是红色节点&#xff08;祖父节点为红色&#xff09;添加不平衡LL/RR添加不平衡LR/RL 叔父节点是红色节点&#xff08;祖父节点为…

【HTML+CSS+JS】登录注册页面大合集

前言 学JS也学了一段时间&#xff0c;正巧碰上了人工智能要调用人脸识别接口进行真人人脸识别&#xff0c;于是便萌生了用人脸来进行注册和登录的想法&#xff0c;这样的话就需要开发一个登录注册页面&#xff0c;然后用JS绑定注册事件调用人脸识别接口进行登录注册 饭要一口一…

vue首屏白屏原因及解决办法

vue首屏白屏原因大概有以下几点&#xff1a; 一.路由模式错误(路由重复或者没有配置路由) &#xff08;1&#xff09;由于把路由模式mode设置成history了&#xff0c;默认是hash 解决方法&#xff1a;将模式改为hash模式&#xff0c;或者直接把模式配置删除&#xff0c;而且hi…

让GPT成为护理专家 - 护士的工作如此简单

引子    书接上文《GPT接入企微应用 - 让工作快乐起来》&#xff0c;我把GPT接入了企微应用&#xff0c;不少同事都开始尝试起来了。有的浅尝辄止&#xff0c;有的刨根问底&#xff0c;五花八门&#xff0c;无所不有。这里摘抄几份&#xff1a; “帮我写一份表白信&#xff…

{.....},正则表达式将{}和{}中的内容全部替换为1

解决办法&#xff1a;replaceAll("\\{.*?\\}", "1") 当在Java字符串中使用正则表达式时&#xff0c;需要注意转义字符的使用。因为在Java中某些字符本身就有特殊含义&#xff0c;例如 \、{、} 等等&#xff0c;如果直接使用这些字符来进行正则表达式匹配…

【水光互补优化调度】基于非支配排序遗传算法的多目标水光互补优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

23. 资源的调度——Pod 优先级调度(Pod Priority Preemption)

本章讲解知识点 Pod 优先级调度QoS1. Pod 优先级调度 1.1 前言 出于各种原因,对于运行各种负载(如:Deployment、StatefulSet、DeamonSet)的中等规模或大规模集群,我们需要尽可能提高其资源利用率。 一种常见的提高资源利用率的方法是采用优先级方案,即为不同类型的负载…