详细讲述C++各种运算符重载

2023-10-31

1、等号运算符重载

我们需要注意的是,当我们不写等号运算符重载的时候,系统会默认生成浅赋值形式等号运算符重载,所谓的浅赋值就是将目标对象的成员属性直接赋值给当前对象(可以参考深拷贝和浅拷贝,在我的“C++——拷贝构造函数详解”这篇文章中有详细讲解)。

Object 
{
public:
//其他的构造函数、析构函数不是本篇文章重点,省略。
    void operator=(const Object& obj)
    {
         this->value=obj.value;
    }
    /*
    在主函数中使用obja=objb=objc,等价于下面的方法调用:
    obja=objb.operator=(objc);
    obja=operator=(&objb,objc);
    */
private:
    int value;
}

对于上述的赋值语句需要说明以下三点:
①这个赋值语句不能用const进行修饰,因为this->value在赋值的过程中有所改变
②这个方法不能实现连续赋值,因为返回值为void,可以将void改成Object,就能实现连续赋值
③由于对象在主函数中,通过引用传参进入当前方法,因此obj对象不受这个重载函数调用期的影响,所以可以用引用进行返回

不写等号运算符重载有两种情况:
①没有自己设计的类型和对象,都是基本类型,那么系统就会将两个对象的成员属性地址抓住,直接目标对象成员属性的数据导入当前对象成员属性中。
②如果成员属性中不止是基本类型,那么如果我们不写等号运算符重载,系统就会产生默认的浅赋值语句。

2、加号运算符重载

class Int
{
private:
   int value;
public:
    //前置加加
   Int& operator++()
   {
       this->value+=1;
       return *this;
   }
    //后置加加
   Int operator++(int)
   {
       Int tmp = *this;
       ++* this;//调用前置加加
       return tmp;
   }
    //对象+对象
   Int operator+(Int& b)const
   {
       Int c;
       c.value   = this->value + b.value;
       return c;
   }
    //对象+数值
   Int operator+(int val)const
   {
       Int c;
       c.value = this->value + val;
       return c;
   }
   
};
//数值+对象
Int operator+(const int val, const Int& a)
{
    return a + val;//调用Int operator+(int val)const 这个方法
}

3、取地址运算符重载

class Int
{
private:
   int value;
public:
   //省略构造函数、等号运算符重载,这里主要说明取地址运算符重载
   Int* operator&()
   {
        return this;
   }
   const Int* operator&()const//加了const的取地址运算符重载是一个常方法
   {
        return this;
   }
}
int main()
{
    Int a(10);
    Int b=10;//这句话会先调用构造函数构造一个value成员属性为10的对象,然后把这个对象赋值给b
    const Int c=10;
    const Int *ip=&c;//因为C是常对象,所以就会调用上面的常方法
}

4、前置++,后置++运算符重载

4.1后置++的引用问题:

因为是后置++,通过下面的代码可知,我们需要创建一个对象用来保存原来的值,然后再将当前值+1.然而创建的这个对象的生存期和重写后置++方法的生存期一样,当函数调用结束,空间就会被释放。所以不可以返回引用。

 //后置加加
   Int operator++(int)
   {
       Int tmp = *this;
       ++* this;//调用前置加加
       return tmp;
   }

但是如果我们非要返回引用,加一个static可不可以呢?如下:

Int& operator++(int)
{
    static Int old=*this;
    ++* this;
    return old;
}

上述代码因为定义成静态,那么当我们执行一次后置++没有问题,但是因为是静态,只执行一次 static Int old=*this;,当我们再次执行后置++的时候,值并不变,还是之前的值,那么我们改成下面的:

Int& operator++(int)
{
    static Int old=*this;
    old=*this;
    ++* this;
    return old;
}

加上old=*this这句话之后,那么我们每执行一次后置加加方法,就会将静态变量old重新赋值给当前的对象,从而避免上述的“再次执行后置++的时候,值并不变,还是之前的值”的问题。
举例对修改之后的代码作以说明:
在这里插入图片描述
最后d输出12,因为有 old=*this;会更新old。

4.2相关问题分析

结合下面的运算符重载,分析Int a=0;a=a++ +1;这句代码。

在这里插入图片描述
在这里插入图片描述

5、重载类型强转运算符

(1)隐式的类型转化:
所谓的隐式类型转化通过下面的例子说明:
a=b,这句话其实是先用整型b的值100进行构造,将构造的这个对象给a赋值,主函数调用结束之后析构这个对象,析构a。
(不允许隐式转换的关键字:explicit)

需要强调的是:能够进行隐式类型转换的的构造函数必须是单个参数的
在这里插入图片描述

(2)强制类型转换:
把对象强转成某一个内置类型

//把对象强转成整型
operator int() const
{
    return value;
} 

强转返回的类型就是强转之后的类型,因此重载函数不需要设置返回类型
例如下面呢的:如果返回flot,就和返回类型冲突。
在这里插入图片描述

6、括号运算符重载

class Add
{
      mutable int value;//加了mutable这个关键字之后,可以让value这个变量在常方法中也能改变
 public:
       Add(int x=0):value(x){};
       int operator()(int a,int b)const//括号运算符重载
       { 
            value=a+b;
            return value;
       } 
}
int main()
{
    int a=10,b=20,c=0;
    Add add;
    c=add(a,b);//调用括号运算符重载,我们也称之为仿函数
    //c=add.operator()(a,b);
    return 0;
}

7、输出运算符重载

下面的输出运算符重载是错误的。必须通过引用来调用out参数,因为系统的代码设置的是私有的输出流,所以必须是引用调用,如果不是引用调用,就会调用拷贝构造,而拷贝构造被设置为私有,无法调用。

class String
{
private:
      char * str;
public:
      //ostream& operator<<(const String* const this,ostream& out)
      ostream& operator<<(ostream out)const
      {
           if(str!=NULL)
           {
                out<<str;
           }
           return out;
      }
      //s1<cout
      //s1.operator<<(cout)
      //operator(&s1,cout)
}

正确的如下:
把str的内容写入搭配out中,并返回
在这里插入图片描述
但是上述的输出运算符重载在使用的时候是:s1<<cout,并不符合我们逻辑的输出运算符重载:
所以:
先调用ostream& operator<<(ostream& out,const String& s)
然后再对象内部调用输出运算符重载

class String
{
private:
      char * str;
public:
      //ostream& operator<<(const String* const this,ostream& out)
      ostream& operator<<(ostream& out)const
      {
           if(str!=NULL)
           {
                out<<str;
           }
           return out;
      }
      //s1<cout
      //s1.operator<<(cout)
      //operator(&s1,cout)
}
ostream& operator<<(ostream& out,const String& s)
{
    s<<out;
    //s.operator<<(out);
    //operator<<(&s,out);
    return out;
} 
int main()
{
     String s1("hello world");
     cout<<s1<<endl<<;
     return 0;
}

8、星号运算符重载

class Int
{
private:
     int value;
};
class Object
{
    Int* ip;//Int是一个类
public:
    Object(Int* s=NULL):ip(s){}
    ~Object()
    {
         if(ip!=NULL)
         {
              delete ip;
         }
         ip=NULL;
    }
    //✳运算符重载返回这个对象所指向的地址
    Int* operator*()
    {
        return ip;
    }
    const Int* operator*()const
    {
        return ip;
    }
    //✳运算符重载返回ip所指向的对象
    Int& operator*()
    {
        return *ip;
    }
    const Int& operator*()const
    {
        return *ip;
    }
};
int main()
{
     Object obj(new Int(10));
     (*obj)->value();
}

9、指向运算符重载

class Int
{
private:
     int value;
};
class Object
{
    Int* ip;//Int是一个类
public:
    Object(Int* s=NULL):ip(s){}
    ~Object()
    {
         if(ip!=NULL)
         {
              delete ip;
         }
         ip=NULL;
    }
    //返回所指向的这个对象的地址
    const Int* operator->()const
    {
        return ip;
    }
}
int main()
{
     Object obj(new Int(10));
     obj->value();
}

注:通过星号运算符重载和指向运算符重载综合运用来实现“对象的使用自由化”问题:
问题引入:

class Int
{
private:
     int value;
};
class Object
{
    Int* ip;//Int是一个类
public:
    Object(Int* s=NULL):ip(s){}
    ~Object()
    {
         if(ip!=NULL)
         {
              delete ip;
         }
         ip=NULL;
    }
    Int& operator*()//重载*,返回ip所指对象本身
    {
         return *ip;
    }
    const Int& operator*()const
    {
         return *ip;
    }
    Int* operator->()
    {
         return &**this;
    }
    const Int* operator->()const
    {
         return &**this;
         //return ip
    }
}

上面的的&**this表示什么呢?

对于上述代码我们结合下图从右往左进行分析:this就是指向obj这个对象,*this表示obj这个对象,然后**this就调用了✳运算符重载,表示ip所指向的这个对象本身,所以这个合起来表示ip所指向的这个对象的地址
在这里插入图片描述
所以进✳运算符和->运算符的重在之后,也能够得到Int对象,并且利用Obj这种形式实现了自由化,也就是说在析构的时候就会自动析构ip所指向堆区的空间,不用我们手动释放。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详细讲述C++各种运算符重载 的相关文章

  • 将 SQL Server varBinary 数据转换为字符串 C#

    我需要帮助弄清楚如何转换来自SQL服务器表列设置为varBinary 最大 转换为字符串以便将其显示在标签中 这是在C 我正在使用数据读取器 我可以使用以下方式提取数据 var BinaryString reader 1 我知道该列包含之前
  • 如何在 C# 中知道 PID 和 VID 来发现虚拟 COM 端口名称

    如果我知道 PID 和 VID 我会尝试找到查找 COM 端口名称的正确方法 到目前为止 我写了解决方法 但我不相信没有更优雅和正确的方法 顺便说一句 我知道我可以使用 REGEX 编写此代码只是为了测试解决方法 我知道还有很大的改进空间
  • binary_log_types.h:没有这样的文件或目录

    我正在编译一个小型 mysql C 项目并且 遇到以下错误 C Program Files x86 MySQL MySQL Server 5 7 include mysql com h 22 30 fatal error binary lo
  • 在 C# 中轻松创建支持索引的属性

    在 C 中我发现索引属性 http msdn microsoft com en us library aa288464 VS 71 aspx非常有用 例如 var myObj new MyClass myObj 42 hello Conso
  • 为什么这个 oracle 批量插入不起作用?

    我正在尝试将一些数据批量插入到 oracle 数据库中 我按照文档中的示例进行操作 this DataBaseAccess new OracleConnection connString var dataAdapter new Oracle
  • std::tr1::function 和 std::tr1::bind

    我在使用时遇到问题veryC 类中的复杂 C 函数 重写 C 函数是not一个选项 C函数 typedef void integrand unsigned ndim const double x void fdata unsigned fd
  • 通过用于 Symbol 条码扫描仪 DS4208 的 SNAPI.dll API 捕获图像

    我想通过 SNAPI API 从 Symbol 目前为 Zebra 条形码扫描仪 DS4208 型号 我们还使用 Zebra 的另一个但兼容的型号 捕获图像 条形码捕获 识别效果很好 但看起来像SnapiDLL SNAPI SnapShot
  • boost::asio::io_service 是否保留处理程序的顺序?

    Does boost asio io service http www boost org doc libs release doc html boost asio reference io service html保证处理程序的调用顺序与
  • 如何在Azure功能中添加razor视图文件?

    我正在创建一个应用程序 它是 azure 函数项目 我想在该项目中使用 Razor 视图 我应该在 azure 函数中使用任何模板引擎吗 得益于一些方面的进步剃刀之光项目 https github com toddams RazorLigh
  • 修改正在运行的可执行文件的资源内容

    All 我将应用程序设置存储在资源中 当我的程序首次加载时 我使用 WinAPI 读取指定的资源 然后我解析检索到的字节数据 这对我来说完美无缺 现在假设用户更改了我的应用程序中的设置 他 她检查复选框控件 我想将更新的设置保存到我的资源中
  • Identity Server 4:添加访问令牌的声明

    我正在使用 Identity Server 4 和隐式流 并且想要向访问令牌添加一些声明 新的声明或属性是 tenantId 和 langId 我已将 langId 添加为我的范围之一 如下所示 然后通过身份服务器请求 但我也获得了tena
  • 为什么这个单独的定义会导致错误?

    挑战 我有这段代码无法编译 你能找出问题所在吗 有一次让我很头疼 header namespace values extern std string address extern int port cpp file std string v
  • 我可以在 C++ 中重写非虚函数吗

    我想知道我可以重写 C 中的非虚函数吗 因为我在使用 C 时发现了这个问题override关键字我的代码如下 class A public void say cout lt lt From A n class B public A publ
  • 将授权标头添加到 Web 参考

    我正在尝试向客户端的网络服务发出请求 我不知道客户端的底层平台 我使用 添加 Web 引用 在 Visual Studio 2010 中使用了客户端的 WSDL 并生成了我的代理类 称为 ContactService 我现在需要将如下所示的
  • 为什么我无法调试动态加载的程序集?

    我正在开发一个 Web API 项目 该项目使用内部模拟框架 允许拦截和修改来自控制器的响应 它使用 MEF 加载包含某些先决条件匹配时执行的代码的程序集 我知道这是正常工作的 因为我可以在响应中看到模拟已被执行 但由于某种原因我无法调试动
  • 使用 _Alignas 进行结构成员对齐

    我想知道以下问题 是新的吗 Alignas结盟 C11 中的说明符适用于结构成员吗 我一直假设这么多 但彻底阅读了 N1570 公开草案似乎表明对齐说明符不能 出现在一个说明符限定符列表 这就是我所期望的 如果得到支持的话 我已经读过几遍语
  • “显式”关键字对返回值优化 (RVO) 有何影响?

    以下代码工作得很好 显示 RVO struct A A int cout lt lt A A n constructor A const A cout lt lt A A const A n copy constructor A foo r
  • 替换全局热键

    我有一个位于托盘中的应用程序 我想定义多个热键来触发我的程序中的事件 我从 AaronLS 在这个问题中的出色回答中找到了灵感 使用C 设置全局热键 https stackoverflow com a 27309185 3064934 如果
  • DataGridView 捕获用户行选择

    我在处理选择时遇到问题DataGridView 我的网格视图包含一个金额列 表单上有一个文本框 应显示所选网格视图行的总数 因此 我需要在用户选择 取消选择 gridview 行时捕获事件并相应地计算 添加 减去 金额 我找到了两种方法 使
  • C#:如何处理乱序 TCP 数据包?

    请有人解释一下如何处理乱序数据包 我使用原始套接字来捕获数据包 并在数据包到来时解析它们 但其中一些数据包的顺序错误 例如 ID 标志 16390 PSH ACK 16535 PSH ACK 16638 确认 16640 PSH ACK 1

随机推荐

  • thanos配置promethes高可用

    参考文档 https www kubernetes org cn 7217 html prometheus高可用方案 prometheus官方的高可用有几种方案 HA 即两套 prometheus 采集完全一样的数据 外边挂负载均衡 HA
  • 从技术布局看,苹果离元宇宙还有多远?

    扎克伯格的Meta元宇宙令人津津乐道 从2021年10月28日更名之始 元宇宙 Metaverse 便开始在各大媒体及圈内人士间被不断谈论 但在此之外 元宇宙的另一个 实力选手 依旧赫然在列 扎克伯格一直把它看作是竞争对手 在一次内部的谈话
  • HarmonyOS开发:解决DevEco Studio低版本导入高版本项目运行失败问题

    前言 基于DevEco Studio 4 0 Beta2 hvigorVersion为3 0 2 开发了一个项目 上传到了远程仓库 当同事下载后 却始终无法运行 频繁报错 由于API都是使用的9 第一感觉就是开发环境不同 于是 让其发来了他
  • go 进阶 gin底层原理相关: 四. gin中间件底层原理

    目录 一 gin 中间件基础 二 中间件初始化流程 1 初始化中间件保存到RouterGroup的HandlersChain数组中 HandlersChain是什么 2 整合中间件函数与业务相关的mainHandler构建前缀树 三 中间件
  • Matlab:自定义绘图颜色

    Matlab 自定义绘图颜色 在 Matlab 中绘制图形时 我们可能需要使用自己指定的颜色来填充线条 散点或者其他图案 这可以让我们的图像更加美观和易读 下面介绍两种常见的设置自定义颜色的方法 使用 RGB 颜色值 RGB 颜色值是一种由
  • idea如何导入一个spring boot 项目

    1 菜单 gt File gt New gt Project From Existing Sources 2 选中项目中的pom xml 3 点击OK 然后后面就一路 Next 直到 finish就行了 需注意你的idea工具中项目jdk和
  • 面试必问 - AES 加密 和 RSA 加密是什么?它们有什么区别

    1 什么是 AES 加密 和 RSA 加密 AES Advanced Encryption Standard 高级加密标准 AES 是一种对称加密算法 即加密和解密使用相同的密钥 AES 的密钥长度可以选择 128 位 192 位或 256
  • Vue中通过localStorage存储信息并获取显示到页面中

    这两天写了一个日程表功能 包括日程表内容的增加 删除功能 解决办法一 可以在后端写接口 把日程表的内容写到数据库中 再通过接口从数据库中获取 通过后端的接口来对数据进行增删改查 解决办法二 这次我没想着做后端接口 因为是写在浏览器首页面中
  • 怎样优化Pentium系列处理器的代码 From:http://www.codingnow.com/2000/download/pentopt.htm#26_14

    How to optimize for the Pentium family of microprocessors Copyright 1996 2000 by Agner Fog Last modified 2000 07 03 Cont
  • Redis集群实现分布式Session共享

    Cookie 保存在客户端浏览器中 而 Session 保存在服务器上 客户端浏览器访问服务器的时候 服务器把客户端信息以某种形式记录在服务器上 这就是 Session 客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就
  • Redis分布式锁的使用和实现原理详解

    这篇文章主要给大家介绍了关于Redis分布式锁的使用和实现原理的相关资料 文中通过示例代码介绍的非常详细 对大家的学习或者工作具有一定的参考学习价值 需要的朋友们下面随着小编来一起学习学习吧 模拟一个电商里面下单减库存的场景 第一版代码 存
  • nn.LayerNorm的实现及原理

    LayerNorm 在transformer中一般采用LayerNorm LayerNorm也是归一化的一种方法 与BatchNorm不同的是它是对每单个batch进行的归一化 而batchnorm是对所有batch一起进行归一化的 y x
  • 是面试官放水,还是公司实在是太缺人?这都没挂,腾讯原来这么容易进···

    本人211非科班 之前在字节和腾讯实习过 这次其实没抱着什么特别大的希望投递 没想到腾讯可以再给我一次机会 还是挺开心的 本来以为有个机会就不错啦 没想到能成功上岸 在这里要特别感谢帮我内推的同学 中间投递比较曲折 是他帮了我很多 非常负责
  • ARM64架构-Ubuntu20更换国内镜像源

    前言 在嵌入式开发中 常用到ARM64的开发平台 进行下载东西时想换国内源 下面以中科大源为参考 一 什么是源 其实吧它就像苹果和案桌的软件应用商店一样 为Linux用户提供软件下载及更新服务的 Linux家族有三个软件源系统 yum源 使
  • 逆向crackme之ESp定律脱壳

    1 前言 此题来自攻防世界高手进阶区的一道逆向题目 crackme 通过对可执行程序进行脱壳 该壳为北斗的壳 涉及到ESP定律 大体流程是找到call处的ESp 在数据窗口中跟随 下个硬件访问断点 就到了OEP处 用ODdump脱壳就行了
  • 使用Docker高效搭建开发环境(详细教程)

    在学习Docker镜像和容器之前 先给大家介绍下Docker的概念 在理解概念的基础上可以举一反三 1 Docker的核心为镜像和容器 有JAVA基础的小伙伴们可以理解为镜像就是JAVA中的类 容器为相关类的对象 一个镜像可以创建多个容器
  • ffmpeg快速将mkv转mp4

    想用pr来剪一些动漫视频 视频是mkv格式的 但是我的pr pro2021不支持mkv格式 只能先转成mp4格式再用pr剪切 ffmpeg的格式转换是最快的 官网下载ffmpeg https github com BtbN FFmpeg B
  • 【环境搭建】(二)在Ubuntu22.04安装/卸载软件Anaconda

    一个愿意伫立在巨人肩膀上的农民 1 Anaconda的主要功能 Anaconda是一个Python环境管理工具 因为不同的Python项目中可能需要同一个库的不同版本 为了避免冲突 Anaconda可以对不同Python项目创建自己的运行环
  • 生活笑话

    n多年前 传呼机还算比较稀罕的时候 有师兄A买了传呼机 师兄B说 要试一试看 好使不 遂打电话到呼台 小姐 请呼 站在那里不要动 等我们过去打你 小姐大惊 这种信息我们不能发 B师兄坚持 就得这么发 不一会儿 呼机响起 拿起一看 有人要打你
  • 详细讲述C++各种运算符重载

    详细讲述C 各种运算符重载 1 等号运算符重载 2 加号运算符重载 3 取地址运算符重载 4 前置 后置 运算符重载 4 1后置 的引用问题 4 2相关问题分析 5 重载类型强转运算符 6 括号运算符重载 7 输出运算符重载 8 星号运算符