26 CPP运算符重载

news2024/11/26 0:41:11

 

 

#include <iostream>

using namespace std;

//非成员函数重载+ -
class Person {
public:
    Person() {
        m_score = 0;
        m_name.clear();
    }

    void show() {
        cout << m_name << " " << m_score << endl;
    }

    int m_score;
    string m_name;
};

//全局重载+号
void operator+(Person &p, int score) {
    p.m_score += score;
}

//全局重载-号
Person &operator-(Person &p, int score) {
    p.m_score -= score;
    return p;
}

void test() {
    Person p;
    p.m_score = 1;
    p + 10;
    p.show();
    p = p - 1 - 2;//同下
//    p = operator-(operator-(p, 1), 2);
    p.show();
}

int main() {
    test();
    return 0;
}
 11
 8
#include <iostream>

using namespace std;

//非成员函数重载+ -
class Person {
public:
    Person() {
        m_score = 0;
        m_name.clear();
    }

    void show() {
        cout << m_name << " " << m_score << endl;
    }

    void operator+(int score) {
        this->m_score += score;
    }

    Person &operator-(int score) {
        this->m_score -= score;
        return *this;
    }

    int m_score;
    string m_name;
};


void test() {
    Person p;
    p.m_score = 1;
    p + 10;
    p.show();
    p = p - 1 - 2;//同下
//    p = operator-(operator-(p, 1), 2);
    p.show();
}

int main() {
    test();
    return 0;
}

注意事项:

1 返回自定义数据类型的引用可以让多个运算符表达式串联起来。(不要返回局部变量的引用)

2 重载函数参数列表中顺序决定了操作数的位置(后面有代码说明)

3 重载函数的参数列表中至少有一个是用户自定义的类型,防止程序员为内置数据类型重载运算符

4 如果运算符重载既可以是成员函数也可以是全局函数,应该优先考虑成员函数,这样更符合运算符重载的初衷。

5 重载函数不能违背运算符原来的含义和优先级。(语法上没有限制不能这么做,但是这么做很垃圾)

6 不能创建新的运算符

7 以下运算符不可以重载

 

 8 以下运算符只能通过成员函数进行重载

 

 重载函数参数列表中顺序决定了操作数的位置 代码说明

#include <iostream>

using namespace std;

//重载函数参数列表中顺序决定了操作数的位置
class Person {
public:
    Person() {
        m_score = 0;
        m_name.clear();
    }

    void show() {
        cout << m_name << " " << m_score << endl;
    }

    int m_score;
    string m_name;
};

Person &operator+(Person &p, int score) {
    p.m_score += score;
    return p;
}

Person &operator+(int score, Person &p) {
    p.m_score += score;
    return p;
}

Person &operator+(Person &p1, Person &p2) {
    p1.m_score += p2.m_score;
    return p1;
}


void test() {
    Person p;
    p.m_score = 1;
    p + 10;
    p.show();
    //如上,重载的时候 Person &p, int score 顺序是这样,那么下面代码将报错
    p + 10 + p;//Invalid operands to binary expression ('void' and 'Person'
    //所以需要再写两个重载,顺序是int score,Person &p和Person &p1, Person &p2
    p.show();
}

int main() {
    test();
    return 0;
}

 

上图 关系运算符和左移运算符重载比较简单,其它几个运算符重载都有一些不一样的地方,C++编译器需要特别的处理。

重载左移运算符

#include <iostream>

using namespace std;

//左移运算符 cout
class People {
    friend ostream &operator<<(ostream &cout, const People &p);

    int m_age;
    int m_score;
public:
    People() {
        m_age = 18;
        m_score = 0;
    }

    ostream &operator<<(ostream &cout) {
        cout << m_age << " " << m_score << endl;
        return cout;
    }
};

ostream &operator<<(ostream &cout, const People &p) {
    cout << p.m_age << " " << p.m_score << endl;
    return cout;
}

void test() {
    People p;
    cout << p << endl;
    p << cout << endl;//如果是成员函数的重载,位置就不对了。
}

int main() {
    test();
    return 0;
}

重载下标运算符

 

 

 

 

 

注意:

1 编译器提供的默认赋值函数,是浅拷贝

2 如果对象不存在堆区内存空间,默认赋值函数可以满足需求,否则需要深拷贝。

3 赋值运算和拷贝构造不同:拷贝构造是指原来的对象不存在,用已存在的对象进行构造;赋值运算是指已经存在了两个对象,把其中一个对象的成员变量的值赋给另外一个对象的成员变量。

#include <iostream>

using namespace std;

//重载赋值运算符
class People {

public:
    int m_age;
    int m_score;
    int *m_ptr;

    People() {
        m_age = 18;
        m_score = 0;
        m_ptr = nullptr;
    }

    ~People() {
        if (m_ptr == nullptr) {
            delete m_ptr;
        }
    }

    void show() {
        cout << m_age << " " << m_score << endl;
        if (m_ptr != nullptr) {
            cout << *m_ptr << endl;
        }
    }

    People &operator=(const People &p) {
        //如果是自己给自己赋值
        if (this == &p) {
            return *this;
        }
        if (p.m_ptr == nullptr) {//如果源对象的指针为空,则清空目标对象的内存和指针
            if (m_ptr != nullptr) {
                delete m_ptr;
                m_ptr = nullptr;
            }
        } else {//源对象指针不为空
            //如果目标对象的指针为空,先分配内存
            if (m_ptr == nullptr) {
                m_ptr = new int;
            }
            //然后把源对象内存中的数据复制到目标对象的内存中
            memcpy(m_ptr, p.m_ptr, sizeof(int));
        }
        m_score = p.m_score;
        m_age = p.m_age;
        cout << "调用了重载赋值函数\n" << endl;
        return *this;
    }
};

void test() {
    People p1, p2;
    p1.m_score = 10;
    p1.m_age = 10;
    p1.m_ptr = new int(2);
    p1.show();
    p2.show();
    p2 = p1;
    p2.show();
}

int main() {
    test();
    return 0;
}
10 10
2
18 0
调用了重载赋值函数

10 10
2

 重载new&delete运算符

 

 

 

 

 

new[]和detele[]与 new和detele基本一致,在实际开发中,类用数组表示的 情况不多见,需要自定义分配内存的情况基本上没有,所以这两

为一个类重在new和delete时,尽管不必显示第使用static,但实际上仍在创建static成员函数 说明:

也就是说,声明这两个成员函数的时候,不管有没有写static关键字,它们都是静态成员函数,所以在这两个函数中,不能访问类的非静态成员。

#include <iostream>

using namespace std;

//为整型动态分配内存
void *operator new(size_t size) {
    cout << "调用了重载的new:" << size << "字节" << endl;
    void *p = malloc(size);
    cout << "申请到的内存地址是:" << p << endl;
    return p;
}

void operator delete(void *ptr) {
    cout << "调用了重载的delete" << endl;
//    if (ptr == 0) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
    if (ptr == nullptr) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
        return;
    }
    free(ptr);
}

void test() {
    //对于我们来说,C++的new和delete缺省屏蔽了全部细节,如果我们重载了new和delete运算符,就可以
    //用自己的代码申请和释放内存了。
    int *p = new int(1);
    cout << "p=" << p << ",*p=" << *p << endl;
    cout << "p=" << (void *) p << ",*p=" << *p << endl;
    delete p;


}

int main() {
    test();
    return 0;
}
/*
调用了重载的new:4字节
申请到的内存地址是:0x7fb2fc405910
p=0x7fb2fc405910,*p=1
p=0x7fb2fc405910,*p=1
调用了重载的delete
*/
#include <iostream>

using namespace std;

//为类动态分配内存  全局
void *operator new(size_t size) {
    cout << "调用了全局重载的new:" << size << "字节" << endl;
    void *p = malloc(size);
    cout << "申请到的内存地址是:" << p << endl;
    return p;
}

void operator delete(void *ptr) {
    cout << "调用了全局重载的delete" << endl;
//    if (ptr == 0) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
    if (ptr == nullptr) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
        return;
    }
    free(ptr);
}

class Person {
public:
    int m_age;
    int m_score;

    Person(int age, int score) {
        m_age = age;
        m_score = score;
        cout << "调用了构造函数Person(int age, int score)" << endl;
    }

    ~Person() {
        cout << "调用了析构函数~Person()" << endl;
    }

    void *operator new(size_t size) {
        cout << "调用了类重载的new:" << size << "字节" << endl;
        void *p = malloc(size);
        cout << "申请到的内存地址是:" << p << endl;
        return p;
    }

    void operator delete(void *ptr) {
        cout << "调用了类重载的delete" << endl;
//    if (ptr == 0) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
        if (ptr == nullptr) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
            return;
        }
        free(ptr);
    }
};

void test() {
    //对于我们来说,C++的new和delete缺省屏蔽了全部细节,如果我们重载了new和delete运算符,就可以
    //用自己的代码申请和释放内存了。
    int *p = new int(1);
    cout << "p=" << p << ",*p=" << *p << endl;
    cout << "p=" << (void *) p << ",*p=" << *p << endl;
    delete p;
    cout << endl;
    Person *p2 = new Person(1, 2);
    cout << "p2的地址是" << p2 << " " << p2->m_age << " " << p2->m_score << endl;
    delete p2;


}

int main() {
    test();
    return 0;
}
调用了全局重载的new:4字节
申请到的内存地址是:0x7ff198c05910
p=0x7ff198c05910,*p=1
p=0x7ff198c05910,*p=1
调用了全局重载的delete

调用了类重载的new:8字节
申请到的内存地址是:0x7ff198c05910
调用了构造函数Person(int age, int score)
p2的地址是0x7ff198c05910 1 2
调用了析构函数~Person()
调用了类重载的delete

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

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

相关文章

毕业设计 - 基于SSH码头船只出行及配套货柜码放 管理系统【源码 + 论文】

文章目录前言一、项目设计1. 模块设计2. 实现效果二、部分源码项目源码前言 今天学长向大家分享一个 java web设计项目: 基于SSH码头船只出行及配套货柜码放 管理系统 一、项目设计 1. 模块设计 对于码头日常管理来说&#xff0c;主要是码头船只的管理&#xff0c;码头信息的…

【leetcode.15】三树枝和

题目描述如上 要点分析&#xff1a; 遍历出所有的情况不难&#xff0c;难的是如果和处理重复的结果 纯暴力&#xff0b;检索的话复杂度为n3&#xff0c;最后面的三个测试点会超时 所以这里使用双指针法进行处理&#xff0c;复杂度会变为n2 算法分析&#xff1a; 为了避免…

Java+SSM家庭理财管理系统(含源码+论文+答辩PPT等)

项目功能简介: 该项目采用技术&#xff1a;SSM框架MySQL数据库Tomcat服务器&#xff0c;项目含有源码、文档、配套开发软件、软件安装教程、项目发布教程等 项目功能介绍&#xff1a; 用户分为系统管理员和普通用户两个角色&#xff0c;普通用户可自行注册登录&#xff0c;系统…

【图像处理】Hough变换人眼虹膜定位【含Matlab源码 387期】

⛄一、数字图像处理简介 图像处理基础教程链接 1 【基础教程】基于matlab图像处理&#xff08;表示方法数据结构基本格式类型转换读取点运算代数运算&#xff09;【含Matlab源码 834期】 2 【基础教程】基于matlab图像处理&#xff08;读写显示运算转换变换增强滤波分析统计&a…

计算机毕设Python+Vue学生宿舍管理系统 (程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【遥感科学】第二章 电磁辐射和地物光谱特性

第二章 电磁辐射与地物光谱特征 一、电磁波谱与电磁辐射 1.1 磁波谱 我们说波谱波谱&#xff0c;那么什么是波&#xff0c;什么是谱呢&#xff1f;注意看&#xff0c;这个男人叫小帅 振动的传播称为波&#xff0c;那电磁波又是啥&#xff1f;啥叫电磁振动&#xff1f; 当电…

docker常用命令记录

1.docker加载镜像 sudo docker load --input rknn-toolkit-1.7.3-docker.tar.gz 2.查看镜像 sudo docker images 3.进入docker容器 sudo docker run -t -i --privileged rknn-toolkit:1.7.3 /bin/bash 4.退出容器 eixt 5.查看所有容器 sudo docker ps -a 6.开启容…

截止12.19--之前的再说,就先说一下今天的事

12/19 错怪colab 软链接实现永久 试一下我在ssh传上文件以后&#xff0c;1080卡还能不能看见了&#xff1a;能&#xff0c;得传到data里。可以在ssh上加上 ln -s 找不到GPU是镜像问题 出现找不到显卡的问题 需要换个镜像 所以速速自学docker吧&#xff0c;太被动了 加号做连…

基于AD Event日志识别黄金票据攻击

01、简介黄金票据(Golden Ticket)是基于Kerberos认证的一种攻击方式&#xff0c;常用来做域控权限维持。当攻击者获取到域内krbtgt帐户的SID和HASH&#xff0c;就可以随意伪造域内管理员用户&#xff0c;再加上域帐户krbtgt的密码基本不会更改&#xff0c;即使域管修改了密码&a…

汇编循环指令(汇编统计正负数汇编语言1到100的求和汇编求一组数最大值)

目录 LOOP指令&#xff08;重点掌握&#xff09; LOOPZ/LOOPE指令 LOOPNZ/LOOPNE指令 例题 一&#xff1a;读程序写结果 二&#xff1a;阅读程序段回答问题 三&#xff1a;读程序写结果 四:求100内的数累和 五&#xff1a;统计正数负数零 六&#xff1a;求字节单元中…

03---后端框架搭建

1、创建项目 打开Ider&#xff0c;创建springboot项目。创建页面勾选需要的依赖&#xff0c;自定义包名、存储位置等&#xff0c;然后创建项目pom依赖如下 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>…

jenkins开发相关

1、jenkins 处理系统配置中publish over ssh中的密码 主机信息数据存储在&#xff5e;/.jenkins/jenkins.plugins.publish_over_ssh.BapSshPublisherPlugin.xml文件中。 java后端如果要加密可以通过以下方法实现。 String Password "xxxx" String passwd "pr…

中科方德服务器操作系统虚拟机安装过程记录

没啥技术含量&#xff0c;就是过程中踩了一些坑&#xff0c;我做个记录&#xff0c;方便后续查阅以及其他人参考什么的。 1、新建虚拟机向导---选择典型配置 2、选择&#xff1a;稍后安装客户机操作系统 3、选择客户机操作 系统以及版本&#xff0c;中科方德服务器系统为在安装…

【LeetCode每日一题】——338.比特位计数

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【题目进阶】九【时间频度】十【代码实现】十一【提交结果】一【题目类别】 动态规划 二【题目难度】 简单 三【题目编号】 338.比特位计数 四【题目描述…

IPv4 ACL访问列表简介、ACL的3种主要分类介绍与配置、以大白话介绍ACL通配符、ACL动作、定义方向、Rule序号。

3.0.0 IPv4 ACL列表&#xff08;简介、ACL分类、ACL配置、通配符&#xff09; ACL访问控制列表简介ACL的分类(华为设备)1、基本/标准ACL基本ACL编号&#xff1a;2000~2999基本ACL的作用&#xff1a;基于数据流的源地址进行匹配2、高级ACL高级ACL编号&#xff1a;3000~3999高级A…

代码随想录刷题记录day46 最长递增子序列+最长连续递增序列+最长重复子数组

代码随想录刷题记录day46 最长递增子序列最长连续递增序列最长重复子数组 300. 最长递增子序列 思想 1.dp数组的定义 dp[i]表示[0,i]区间的最长递增子序列 2.递推公式 如果num[i]>num[j];dp[i]dp[j]1 其中j从0到i-1遍历 3.初始化 所有的都初始化为1 4.遍历顺序 从…

一文读懂于Zebec生态中的潜在收益方式

随着加密市场逐渐陷入低谷&#xff0c;曾经火热的NFT、GameFi等赛道都陷入了沉寂。投资者目前很难在加密市场中获得可观的收益&#xff0c;而在整体加密市场发展局势不明朗的情况下&#xff0c;行业目前缺乏发展动力。 目前&#xff0c;以流支付为主要定位的Zebec生态&#xff…

docker-compose入门以及部署SpringBoot+Vue+Redis+Mysql(前后端分离项目)以若依前后端分离版为例

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客_前后端分离的项目怎么运行 上面在搭建起来前后端分离版的项目后。 如果想通过Dockerfile的方式部署项目可以参考如下。…

沃尔玛账号被冻结后如何进行申诉?

目前申请一个沃尔玛店铺并不容易&#xff0c;但仍有不少卖家因为操作不当导致账号被冻结封禁&#xff0c;这对于国内的卖家来说是巨大的损失。那么要如何避免账号被冻结&#xff0c;冻结后又该如何申诉呢&#xff1f;如何避免账号被冻结&#xff1f; 一、保证店铺表现符合平台标…

纵向分栏

【问题】 I would like to create a table that should be vertical orientation, that means each resultset row should filled from left to right.. Can i achieve this without using crosstab? 【回答】 横向分栏的功能可以先用集算器把数据准备好作为普通报表实现&…