浅谈C++|运算符重载


重载原因

C++ 中的运算符重载是一种特性,允许程序员定义自定义类类型的运算符操作。通过运算符重载,可以对类对象执行类似于内置类型的操作,例如加法、减法、乘法等。

运算符重载通过定义特定的成员函数或非成员函数来实现。成员函数的运算符重载为类的成员函数,且至少需要一个类对象作为操作数。而非成员函数的运算符重载则是独立于类的函数,其参数可以是类对象、指针或者引用。

运算符重载使用特定的语法,以便将运算符关联到相应的函数实现。例如,对于双目运算符(如+、-、*),可以通过重载成员函数或非成员函数的方式定义其操作。其中,成员函数的运算符重载使用成员函数的方式进行调用,而非成员函数的运算符重载则使用运算符的左侧对象作为第一个参数。

运算符重载提供了方便和直观的方式来执行类对象之间的操作。它可以使代码更具可读性,并提供更自然的语义,使得类的行为更接近内置类型。

然而,运算符重载也需要谨慎使用。过度使用运算符重载可能会导致代码可读性下降,使得代码难以理解和维护。因此,在进行运算符重载时,应注意遵循适当的语义和约定,并且避免使用过于复杂或混淆的运算符重载实现。

总结来说,C++ 中的运算符重载是一种强大的特性,允许程序员定义自定义类类型的运算符操作。通过合理和适度地使用运算符重载,可以提高代码的可读性和可维护性,使类对象的操作更加自然和直观。

一.加号运算符重载

对于内置的数据类型的表达式的运算符是不可能改变的

不要滥用运算符重载 

1.1成员函数实现

成员函数实现时,即使成员函数是私有变量,也是可以实现运算符重载的,并且支持函数重载。

代码: 

#include <iostream>
using namespace std;
class person {
friend void fun();
private:int age;int year;
public:person(int age, int year) :age(age), year(year) {}person(){}person operator+(person& p) {person m;m.age = this->age + p.age;m.year = this->year + p.year;return m;}
};
void fun() {person a(10, 90);person b(34, 89);person c = a + b;cout << c.age << ' ' << c.year << endl;
}
int main() {fun();return 0;
}

此时person c = a + b本质是person c=a.operator+(b);

person d = a + 10本质是person d=a.operator+(10);

 2.2全局函数实现

全局函数实现时,重载运算符函数不能直接访问私有成员变量,需要在类中声明友元。

代码: 

#include <iostream>
using namespace std;
class person {
friend void fun();   //设置全局函数是友元
friend person operator+(person& p1, person& p2);
friend person operator+(int p, person& p1);
private:int age;int year;
public:person(int age, int year) :age(age), year(year) {}person(){}
};person operator+(person& p1,person& p2) {person m;m.age =p1.age + p2.age;m.year =p1.age + p2.year;return m;
}person operator+(int p,person& p1) {   //函数重载person m;m.age = p1.age + p;m.year = p1.year + p;return m;
}
void fun() {person a(10, 90);person b(34, 89);person c = a + b;person d = 10+ a;  cout << c.age << ' ' << c.year << endl;cout << d.age << ' ' << d.year << endl;
}
int main() {fun();return 0;
}

此时,person c = a + b;  本质是person c =operator+(a,b);
           person d = 10+ a;  本质是person d =operator+(10,a);

 二.左移运算符重载

2.1成员函数实现

成员函数只能实现p<<cout......类型,cout不能放在左边;

 代码:

#include <iostream>
using namespace std;
class person {
private:int age;int year;
public:person(int age,int year):age(age),year(year){}person() {};//返回ostream&是为了链式调用ostream& operator<<(ostream& cout) {cout << this->age << ' ' << this->year;return cout;}
};
void fun() {person p(23,78);p << cout << "成功" << endl;//本质p.operator<<(cout)<<"成功"<<endl;
}
int main() {fun();return 0;
}

p << cout << "成功" << endl的本质是p.operator<<(cout)<<"成功"<<endl;

 2.2全局函数实现

全局函数可以实现cout在类的左边,也可以实现在类的右边

代码:

#include <iostream>
using namespace std;
class person {
friend ostream& operator<<(ostream& cout, person& p);
private:int age;int year;
public:person(int age, int year) :age(age), year(year) {}person() {};//返回ostream&是为了链式调用
};
ostream& operator<<(ostream& cout,person& p) {cout << p.age << ' ' << p.year;return cout;
}
void fun() {person p(23, 78);cout<< p << "成功" << endl;//本质p.operator<<(cout)<<"成功"<<endl;//本质operator<<(cout,p)<<"成功"<<endl;
}
int main() {fun();return 0;
}

三.++运算符重载

前置++重载不用参数,返回值是引用类型,后置++重载要int占位参数,返回值是值。

 31.前置++

代码: 

#include <iostream>
using namespace std;
class myint {
friend ostream& operator<<(ostream& cout, myint& p);
public:myint(int age,int year):age(age),year(year){}myint(){}//重载前置++,返回*this也是为了链式调用myint& operator++() {this->age++;return *this;}
private:int age;int year;
};
//重载<<运算符,注意是ostream& cout,是引用类型
ostream& operator<<(ostream& cout, myint &p) {cout << p.age << ' ' << p.year;return cout;
}
void fun() {myint p(10, 20);cout << ++(++p) << endl;;
}
int main() {fun();return 0;
}

 返回追是引用类型,如果返回普通值的话,只能自增一次,第二次只是改变副本。

3.2后置 ++

代码:

#include <iostream>
using namespace std;
class myint {
friend ostream& operator<<(ostream& cout, myint& p);
friend void fun1();
public:myint(int age,int year):age(age),year(year){}myint(){}//重载前置++,返回*this也是为了链式调用myint& operator++() {this->age++;return *this;}//重置后置++,返回之前副本。myint operator++(int) {myint m = *this;this->age++;return m;}
private:int age;int year;
};
//重载<<运算符,注意是ostream& cout,是引用类型
ostream& operator<<(ostream& cout, myint &p) {cout << p.age << ' ' << p.year;return cout;
}
void fun() {myint p(10, 20);cout << ++(++p)<<endl;;
}
void fun1() {myint p(10, 20);cout << (p++).age << endl;cout << p.age << endl;
}
int main() {fun1();return 0;
}

后置++用int占位参数,用来区分和前置++的区别,并且要注意,返回的是值类型

 四.赋值运算符重载

 在实例化类的对象时,会自动创建一个operator=函数,不过此时是浅拷贝,当遇到建立到堆上的数据类型时。调用赋值运算符会报错。此时需要重载赋值运算符,将浅拷贝改为深拷贝。

代码:

#include <iostream>
using namespace std;
class person {
public:int* age;int year;//有参构造,在堆区开辟person(int age, int year) {this->age = new int(age);this->year = year;}//深拷贝person(const person& p) {year = p.year;age = new int(*p.age);}//返回值是引用类型,链式调用person& operator=(const person& p) {if (this->age != NULL) {delete age;age = NULL;}year = p.year;//深拷贝age = new int(*p.age);   return *this;}~person() {if (this->age != NULL) {delete age;age = NULL;}}
};
void fun() {person p1(43, 78);person p2(4, 7);person p3(89, 90);p3=p2 = p1;cout << *p2.age << ' ' << p2.year << endl;cout << *p3.age << ' ' << p3.year << endl;
}
int main() {fun();return 0;
}

p3=p2 = p1的本质是p3.operator=(p2.operator=(p1))

 五.函数调用运算符重载

·函数调用运算符()也可以重载

·由于重载后使用的方式非常像函数的调用,因此称为仿函数,仿函数没有固定写法,非常灵活

 代码:


#include <iostream>
using namespace std;
class person {
public:int age;person(int age) {this->age = age;}person(){}void operator()(string name) {cout << name << endl;}void operator()() {cout << "年龄是:" << age << endl;}
};
void fun() {person p1(10);person p2(20);p1("name_name");//匿名对象person()("匿名调用");p1();p2();
}
int main() {fun();return 0;
}

六.关系运算符重载

作用:重载关系运算符,可以让两个自定义类型对象进行对比操作

 代码:

#include <iostream>
using namespace std;
class person {
public:int age;string name;person(int age, string name) :age(age), name(name) {}//重载==号,函数设置为常函数是为了防止误操作bool operator==(const person& p)  const{if (age == p.age && name == p.name) {return true;}return false;}//重载!=号bool operator!=(const person& p) const  {if (age == p.age && name == p.name) {return false;}return true;}//重载>号bool operator>(const person& p) const {if (age == p.age) {return name > p.name;}else {return age > p.age;}}};
void fun() {person p1(40, "tom");person p2(10, "aom");if (p1 == p2) {cout << "p1=p2" << endl;}else {cout << "p1!=p2" << endl;}if (p1 != p2) {cout << "p1!=p2" << endl;}else {cout << "p1==p2" << endl;}if (p1 > p2) {cout << "p1 > p2" << endl;}else {cout << "p1 <= p2" << endl;}
}
int main() {fun();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82634.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring 依赖注入和循环依赖

一.依赖注入的方式 依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;是一种软件设计模式和编程技术&#xff0c;用于实现类之间的解耦和依赖关系的管理。它的核心思想是&#xff1a;在对象创建时&#xff0c;由外部容器负责将该对象所依赖的其他对象&a…

【react】慎用useLayoutEffect转而使用useEffect

由于useLayoutEffect钩子是在dom获得后、渲染组件前。因此&#xff0c;如果在useLayoutEffect中设置一些长耗时的&#xff0c;或者死循环之类的任务&#xff0c;会导致内存堆栈溢出。这时候需要转用useEffect。 // 适配全局宽度拉动变化时&#xff0c;legend显示数量React.use…

OpenAI 模型列表模型

〖ChatGPT实践指南 - 零基础扫盲篇⑧〗- OpenAI 的 模型(Model) 介绍 最新模型描述最大 TOKENS训练日期 gpt-4比任何 GPT-3.5 模型都更强大&#xff0c;能够执行更复杂的任务&#xff0c; 并针对聊天进行了优化。将使用我们最新的模型迭代进行更新。 8,192 tokens Up to Sep 20…

[git] 撤销已经push的提交

1.首先先撤销在本地的commit&#xff1a; git reset --soft HEAD~1这段的意思是撤销最近的一次commit&#xff0c;并且保留工作区的修改。 2.撤销了commit之后&#xff0c;使用git push提交变更到远程 git push origin <本地分支名>:<远程分支名> -f注意&#…

【Linux】shell 提示符

​ Shell俗称壳程序&#xff0c;是一种由C语言编写的用于和操作系统交互的命令解析器软件。它用来接收用户输入命令&#xff0c;然后调用相应的应用程序。 Shell同时又是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命令或者自动地解释和执行预先…

PyG-GAT-Cora(在Cora数据集上应用GAT做节点分类)

文章目录 model.pymain.py参数设置运行图 model.py import torch.nn as nn from torch_geometric.nn import GATConv import torch.nn.functional as F class gat_cls(nn.Module):def __init__(self,in_dim,hid_dim,out_dim,dropout_size0.5):super(gat_cls,self).__init__()s…

java学习--day6(数组)

文章目录 day5作业今天的内容1.数组1.1开发中为啥要有数组1.2在Java中如何定义数组1.3对第二种声明方式进行赋值1.4对数组进行取值1.5二维数组【了解】1.6数组可以当成一个方法的参数【重点】1.7数组可以当成一个方法的返回值1.8数组在内存中如何分配的【了解】 2.数组方法循环…

PFEA111–20 PFEA111–20 人工智能如何颠覆石油和天然气行业

PFEA111–20 PFEA111–20 人工智能如何颠覆石油和天然气行业 人工智能(AI)和机器学习(ML)等新技术的到来正在改变几十年来行业的运营方式。这些技术正在带来革命性的变革&#xff0c;影响着整个行业。石油和天然气行业在其运营过程中面临着许多挑战&#xff0c;如未连接的环境…

在SpringBoot项目中整合SpringSession,基于Redis实现对Session的管理和事件监听

1、SpringSession简介 SpringSession是基于Spring框架的Session管理解决方案。它基于标准的Servlet容器API&#xff0c;提供了Session的分布式管理解决方案&#xff0c;支持把Session存储在多种场景下&#xff0c;比如内存、MongoDB、Redis等&#xff0c;并且能够快速集成到Spr…

AI 标注终结人工标注,效率高 100 倍,成本为 14%

AI 标注终结人工标注,效率高 100 倍,成本为 14% 稀缺性如何解决数据标注廉价的新方法数据标注自动化AnthropicAutolabel 安装 (Python)AI 标注终结人工标注,效率高 100 倍,成本为 14% 稀缺性 大模型满天飞的时代,AI行业最缺的是什么 算力(显卡)高质量的数据OpenAI 正…

Java21 LTS版本

一、前言 除了众所周知的 JEP 之外&#xff0c;Java 21 还有更多内容。首先请确认 java 版本&#xff1a; $ java -version openjdk version "21" 2023-09-19 OpenJDK Runtime Environment (build 2135-2513) OpenJDK 64-Bit Server VM (build 2135-2513, mixed mo…

activiti7的数据表和字段的解释

activiti7的数据表和字段的解释 activiti7版本有25张表&#xff0c;而activiti6有28张表&#xff0c;activiti5有27张表&#xff0c;绝大部分的表和字段的含义都是一样的&#xff0c;所以本次整理的activiti7数据表和字段的解释&#xff0c;也同样适用于activiti6和5。 1、总览…

pcl--第五节 点云表面法线估算

估算点云表面法线 * 表面法线是几何表面的重要属性&#xff0c;在许多领域&#xff08;例如计算机图形应用程序&#xff09;中大量使用&#xff0c;以应用正确的光源以产生阴影和其他视觉效果。 给定一个几何表面&#xff0c;通常很难将表面某个点的法线方向推断为垂直于该点…

python execute() 使用%s 拼接sql 避免sql注入攻击 好于.format

1 execute(参数一:sql 语句) # 锁定当前查询结果行 cursor.execute("SELECT high, low, vol FROM table_name WHERE symbol %s FOR UPDATE;"% (symbol,)) 2 .format() cursor.execute("SELECT high, low, vol FROM table_name WHERE symbol {} FOR UPDATE;…

Pytorch实现LSTM预测模型并使用C++相应的ONNX模型推理

Pytorch实现RNN模型 代码 import torch import torch.nn as nnclass LSTM(nn.Module):def __init__(self, input_size, output_size, out_channels, num_layers, device):super(LSTM, self).__init__()self.device deviceself.input_size input_sizeself.hidden_size inpu…

CockroachDB集群部署

CockroachDB集群部署 1、CockroachDB简介 CockroachDB(有时简称为CRDB)是一个免费的、开源的分布式 SQL 数据库&#xff0c;它建立在一个事务性和强一致性的键 值存储之上。它由 PebbleDB(一个受 RocksDB/leveldb 启发的 K/B 存储库)支持&#xff0c;并使用 Raft 分布式共识…

TypeScript入门

目录 一&#xff1a;语言特性 二&#xff1a;TypeScript安装 NPM 安装 TypeScript 三&#xff1a;TypeScript基础语法 第一个 TypeScript 程序 四&#xff1a;TypeScript 保留关键字 空白和换行 TypeScript 区分大小写 TypeScript 注释 TypeScript 支持两种类型的注释 …

初识C语言——详细入门一(系统性学习day4)

目录 前言 一、C语言简单介绍、特点、基本构成 简单介绍&#xff1a; 特点&#xff1a; 基本构成&#xff1a; 二、认识C语言程序 标准格式&#xff1a; 简单C程序&#xff1a; 三、基本构成分类详细介绍 &#xff08;1&#xff09;关键字 &#xff08;2&#xf…

fork函数

二.fork函数 2.1函数原型 fork()函数在 C 语言中的原型如下&#xff1a; #include <unistd.h>pid_t fork(void);其中pid_t是一个整型数据类型&#xff0c;用于表示进程ID。fork()函数返回值是一个pid_t类型的值&#xff0c;具体含义如下&#xff1a; 如果调用fork()的…

MyBatis中当实体类中的属性名和表中的字段名不一样,怎么办

方法1&#xff1a; 在mybatis核心配置文件中指定&#xff0c;springboot加载mybatis核心配置文件 springboot项目的一个特点就是0配置&#xff0c;本来就省掉了mybatis的核心配置文件&#xff0c;现在又加回去算什么事&#xff0c;总之这种方式可行但没人这样用 具体操作&…