c++运算符重载

2023-09-14 09:21:41

目录

运算符重载的基本概念

重载加号运算符(+)

类内实现

类外实现

运算符重载碰上友元函数

可重载和不可重载的运算符

可重载的运算符

不可重载的运算符

重载自加自减运算符(a++ ++a)

智能指针

重载等号运算符(=)

重载等于和不等运算符(==  !=)


运算符重载的基本概念

概念:

运算符重载与函数重载比较类似,相当于让一个运算符具有另外一种含义;

语法:

定义重载的运算符就像定义函数,只是该函数的名字是 operator@,这里的@代表了被重载的运算符。函数的参数中参数个数取决于两个因素。运算符是一元(一个参数)的还是二元(两个参数);运算符被定义为全局函数(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数-此时该类的对象用作左耳参数)

重载加号运算符(+)

类内实现

#include <iostream>

using namespace std;

class person
{
    public:
        person(int age)
        {
            this->age = age;
        }
        person operator+(person &p2)//
        {
            person p = (this->age+p2.age);
            return p;
        }
        int age;
};
void test01()
{
    person p1(10);
    person p2(20);
    person p3 = p1 + p2;
    cout << p3.age << endl;

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


类外实现

#include <iostream>

using namespace std;

class person
{
    public:
        person(int age)
        {
            this->age = age;
        }

        int age;
};

person operator+(person &p1,person &p2)//
{
    person p = (p1.age+p2.age);
    return p;
}

void test01()
{
    person p1(10);
    person p2(20);
    person p3 = p1 + p2;
    cout << p3.age << endl;

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

运算符重载碰上友元函数

将左移运算符的重载函数声明为类的友元函数 就可以访问类的成员

#include <iostream>

using namespace std;

class person
{
    friend ostream & operator<<(ostream &cout,person &p);
    public:
        person(int age)
        {
            this->age = age;
        }
    private:
        int age;
};

ostream & operator<<(ostream &cout,person &p)
{
    cout << p.age;
    return cout;
}

void test01()
{
    person p1(10);
    cout << p1 << endl;

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

可重载和不可重载的运算符

几乎c 中所有的运算符都可以重载,但运算符重载的使用时相当受限制的。特别是不能使用c 中当前没有意义的 运算符( 例如用 ** 求幂 ) 不能改变运算符优先级,不能改变运算符的参数个数。这样的限制有意义,否则,所有这些行为产生的运算符只会混淆而不是澄清寓语意。

可重载的运算符

不可重载的运算符

重载自加自减运算符(a++ ++a)

a++是先把a赋值到一个临时空间,再对a+1赋值给临时变量,等运算结束后才返回临时变量给a  (参与运算的是自加之前的值)

++a是先给a+1,直接对a赋值,不需要开辟临时空间(参与运算的是返回值的引用)

前置++返回的是引用

后置++返回的是对象

前置++调用void operator++()

后置++调用myint operator++(int) 后置++多了一个占位参数

#include <iostream>

using namespace std;

class myint
{
    public:
        myint &operator++()
        {
            this->num = this->num+1;
            return *this;
        }
        myint(int num)
        {
            this->num = num;
        }
        myint operator++(int)
        {
            myint tmp = *this;

            this->num = this->num+1;
            return tmp;
        }

        int num;
};

ostream &operator<<(ostream& cout,myint &p)
{
    cout << p.num;
    return cout;
}#include <iostream>

using namespace std;

class myint
{
    public:
        myint &operator++()
        {
            this->num = this->num+1;
            return *this;
        }
        myint(int num)
        {
            this->num = num;
        }
        myint operator++(int)
        {
            myint tmp = *this;

            this->num = this->num+1;
            return tmp;
        }

        int num;
};

ostream &operator<<(ostream& cout,myint &p)
{
    cout << p.num;
    return cout;
}

void test01()
{
    myint p1(10);
    cout << p1 << endl;
    ++p1;//调用operator++(p1)或者p1.operator()
    cout << ++p1 << endl;
    p1++;
    //cout << p1++ << end; //有些编译器会报错
    cout << p1 << endl;
}
int main()
{
    test01();
    return 0;
}

智能指针

我们经常new出一个对象,忘记释放,所以我们使用智能指针来维护

智能指针实质上是一个局部对象 这个局部对象维护了new出来的对象的地址,在局部对象的析构函数中,会帮忙释放new出来的对象

对于智能指针我们重载了->和* 让智能指针和普通指针一样使用

#include <iostream>

using namespace std;

class person
{
    public:

        person(int age )
        {
            this->age = age;
        }
        int age;
};

class SmartPointer
{
    public:
        SmartPointer(person *p1)
        {
            this->p = p1;
        }
        ~SmartPointer()
        {
            delete p;
            cout << "释放了p" << endl;
        }
        person *p;
};

void test01()
{
    //局部对象 在释放之前可以帮助释放p
    person *p = new person(10);
    SmartPointer s1(p);
    cout << p->age <<endl;
    cout << 
}
int main()
{
    test01();
    return 0;
}

重载等号运算符(=)

编译器默认给每个类加上了四个函数

        默认的无参构造

        默认的拷贝构造

        析构函数

        operator=()

#include <iostream>
#include <string.h>

using namespace std;

class person
{
    public:
        person()
        {

        }

        person(int agel,char *namel)
        {
            age = agel;
            name = new char[strlen(namel)+1];
            strcpy(name,namel);
        }

        person& operator=(person &p1)
        {
            this->age = p1.age;
            this->name = new char[strlen(p1.name)+1];
            strcpy(this->name,p1.name);

            return *this;//返回p2 为什么不返回p1?可以连续赋值 p3 = p2 = p1
        }

        ~person()
        {
            delete []name;
        }
        int age;
        char *name;
};

void test01()
{
    person p1(10,(char *)"bob");
    person p2;
    p2 = p1;//p2.operator(person &p1)
    cout << p2.age << " " << p2.name <<endl;
}

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

重载等于和不等运算符(==  !=)

#include <iostream>
#include <string.h>

using namespace std;

class person
{
    public:
        person()
        {

        }
		bool operator==(person &p2)
        {
			return this->age == p2.age && this->name == p2.name;
		}
		bool operator!=(person &p2)
        {
			return this->age != p2.age || this->name != p2.name;
		}
        person(int age,string name)
        {
            this->age = age;
            this->name = name;
        }
        int age;
        string name;
};

void test01()
{
	person p1(10,"lucy");
	person p2(10,"bob");
	if(p1 == p2)
	{
		cout << "p1 = p2" << endl;
	}
	if(p1 != p2)
	{
		cout << "p1 != p2" << endl;
	}
}

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

函数调用符号()重载

一个类中重载了()的类,那么类的定义出来的对象可以像函数一样使用,本质是调用了operator()这个函数

#include <iostream>
#include <string.h>

using namespace std;

class Myadd
{
    public:
		int add(int a,int b)
		{
			return a + b;
		}
	int operator()(int x,int y)
	{
		return x + y;
	}
};

void test01()
{
	Myadd p;
	cout << p.add(3,5) << endl;
	//p() 可以像函数一样调用的对象 函数对象
	cout << p(3,4) << endl;//p.operator()(3,4)
	cout << Myadd()(3,4) << endl;//定义一个匿名对象 Myadd().operator()(3,4)
}

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


尽量不要重载 || &&

不能重载 operator&& operator|| 的原因是,无法在这两种情况下实现内置操作符的完整语义。说得更具体一 些,内置版本版本特殊之处在于:内置版本的&& || 首先计算左边的表达式,如果这完全能够决定结果,就无需计算右边的表达式了-- 而且能够保证不需要。我们都已经习惯这种方便的特性了。 我们说操作符重载其实是另一种形式的函数调用而已,对于函数调用总是在函数执行之前对所有参数进行求值。
class Complex{
public :
        Complex( int flag)
        {
                this ->flag = flag;
        }
        Complex& operator +=(Complex& complex)
        {
                this ->flag = this ->flag + complex.flag;
                return * this ;
        }
        bool operator &&(Complex& complex)
        {
                return this ->flag && complex.flag;
        }
public :
        int flag;
};
int main(){
        Complex complex1( 0 ); //flag 0
        Complex complex2( 1 ); //flag 1
        //原来情况,应该从左往右运算,左边为假,则退出运算,结果为假
        //这边却是,先运算( complex1+complex2 ),导致, complex1 flag 变为         complex1+complex2 的值,complex1.a = 1
        // 1 && 1
        //complex1.operator&&(complex1.operator+=(complex2))
        if (complex1 && (complex1 += complex2))
        {
                //complex1.operator+=(complex2)
                cout << " !" << endl;
        }
        else {
                cout << " !" << endl;
        }
        return EXIT_SUCCESS;
}

符号重载总结

1.=, [], () -> 操作符只能通过成员函数进行重载
        例如 :p = 3 成员函数实现 p.operator=(3) 全局函数实现 operator(3,p) 如果把3写在左边 相当于 3 = p,将p赋值给3,但3是一个常量,常量不能作为左值
               
2.<< >> 只能通过全局函数配合友元函数进行重载
        例如:cout << p 因为要把cout放在操作符的左侧 不可能去修改标准库中的类 所以必须配合全局函数和友元函数进行重载
3.不要重载 && || 操作符,因为无法实现短路规则
        内置版本的&& || 首先计算左边的表达式
常规建议
更多推荐

ElasticSearch系列-简介与安装详解

全文检索讲ElasticSearch之前,需要先提一下全文检索.全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程。索引:建立索引文本---->切分--->词文章出现过出现多少次检索:查询关键词---

基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(三)

目录前言总体设计系统整体结构图系统流程图运行环境模块实现1.模型训练1)数据集分析2)数据预处理3)模型创建(1)定义参数(2)定义网络数据输入占位符(3)定义用户嵌入矩阵(4)定义电影嵌入矩阵(5)定义电影类型嵌入矩阵(6)处理电影名称(7)全连接层(8)定义计算图相关其它博客工程源代码下载其它资料下载前言本项目专注

MySQL事务

MySQL事务一、事务的概念二、事务的ACID特点1、原子性2、一致性3、隔离性3.1、事务的隔离级别3.1.1测试脏读3.1.2测试提交读3.1.3测试可重复读3.2、查询全局事务隔离级别3.3、查询会话事务隔离级别3.4、设置全局事务隔离级别3.5、设置会话事务隔离级别4、持久性三、事务控制语句1、测试提交事务2、

SQL如何从数据库中查找数据是否存在

SQL查找是否存在,别再用count!!!问题背景在业务开发中,经常遇到如下需求:从数据库中查找符合一组条件的数据是否存在。结果也无非两种状态:“有”或者“没有”。模拟数据表CREATETABLE`user`(`id`bigintNOTNULLCOMMENT'id',`userName`varchar(256)CHAR

springboot集成canal实现同步双写

一.canal服务端canal是阿里巴巴MySQL数据库Binlog的增量订阅&消费组件。基于数据库增量日志解析,提供增量数据订阅&消费。二.基于docker搭建在docker环境中1.执行dockersearchcanal获取到需要下载的canal镜像2.执行dockerpull选择下载的canal镜像3.执行run

K8S之Pod详解

Pod详解一、Pod基础概念1.概念2.在Kubrenetes集群中Pod有如下两种使用方式3.pause容器使得Pod中的所有容器可以共享两种资源4.kubernetes中的pause容器主要为每个容器提供以下功能5.Kubernetes设计这样的Pod概念和特殊组成结构有什么用意6.通常把Pod分为两类二、容器的分

华为云创新中心&黑湖科技:将智能制造进行到底

编辑:阿冒设计:沐由一如去年,第二届828B2B企业节从8月28日-9月15日期间,再一次成为广大企业界关注的焦点。当前,数字技术已经被广泛被融入到产品、服务与流程当中,用以转变客户的业务成果,以及商业与公共服务的传统交付方式,从而为企业在数字化时代的发展提供了新的契机。华为云联合多方生态伙伴共同发起的828B2B企业

CentOS 7 安装Libevent

CentOS7安装Libevent1.下载安装包新版本是libevent-2.1.12-stable.tar.gz。(如果你的系统已经安装了libevent,可以不用安装)官网:http://www.monkey.org/~provos/libevent/2.创建目录#mkdirlibevent-stable3.解压#

【openwrt学习笔记】miniupnpd学习笔记

目录一、参考资料二、upnp基本概念三、miniupnpd3.1参数说明3.1.1configupnp的配置参数表3.1.2configperm_rule许可设置配置参数表3.2windows上使用miniupnpc工具3.3关于开启upnp功能后无法添加端口四、其它知识补充4.1NAT4.1.1NAT概念4.1.2N

无(低)代码开发思路介绍

无代码或者低代码开发的思路,是通过非编程代码,而是基于页面拖拉拽的方式来实现创建web应用的功能。作为程序员我们知道私有云公有云已经实现了基础设施的web方式管理。DEVOPS把代码发布,管理也实现了web方式管理。那么我们很容易能够想到,只要把拖拉拽出来的项目自动化部署到私有云或者公有云中,就可以实现应用的自动化创建

Linux磁盘管理

物理设备的命名规则在linux系统中一切都是文件,硬件设备也不例外。即然是文件,就必须有文件名称。系统内核中的udev设备管理器会自动把硬件名称规范起来,目的是让用户通过设备文件的名字可以看出设备大致的属性以及分区信息等;在linux中常见的设备文件都存放/dev目录下。下表所显示的就是Linux系统中常见的硬件设备的

热文推荐