浅谈C++

2023-11-14


重载原因

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;
}

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

浅谈C++ 的相关文章

随机推荐

  • 超好玩地铁跑酷游戏,内涵源代码

    直接上代码 include
  • java的多重循环和程序调试

    java的多重循环和程序调试 一 掌握Java二重循环 多重 嵌套 注意 1 外层循环控制行 内层循环控制列 每行打印的内容 2 外层循环执行一次 内层循环执行一遍 3 一般多重循环值的就是二重循环 二 使用跳转语句控制程序的流程 retu
  • 在线Plist文件格式转Json文件格式

    Plist文件是一种用于存储应用程序配置信息的文件格式 其中包含应用程序的各种设置和数据 在过去 Plist文件通常是以 plist 格式存储的 然而 随着时间的推移 人们开始使用 JSON 格式来存储更复杂的数据结构和数据 如果您需要将
  • 国人自研开源项目,一款简单易用的 GitLab 替代品

    公众号关注 GitHubDaily 设为 星标 每天带你逛 GitHub 今天跟大家介绍一个国人自研项目 可用做 GitLab 替代品 PS 本文来自作者本人投稿 OneDev 是一个开源的一体化的 DevOps 平台 目前项目在 GitH
  • 机器学习之网格搜索技术,如何在Auto-sklearn中应用网格搜索技术

    文章目录 一 机器学习中的网格搜索技术是怎么回事 二 通俗解释 三 在一般情况下使用网格搜索技术 四 GridSearchCV网格搜索技术的原理 五 如何在Auto sklearn中使用网格搜索技术 1 Auto sklearn实际用应用中
  • python3 爬取今日头条文章(巧妙避开as,cp,_signature)

    使用环境 python3 scrapy win10 爬取思路 一 关于as cp的生成与 signature的想法 对于今日头条的爬虫 网上搜索出来的文章大多是基于崔庆才 通过搜索爬取美女街拍的方案 怎么说呢 类似这样的虽说是个巧办法 但是
  • RPC研究

    深入浅出RPC 深入篇 mindwind 2014 09 22 出处 http mindwind me blog 2014 09 22 深入浅出RPC 深入篇 html 解析 RPC 的本质 深入篇 我们主要围绕 RPC 的功能目标和实现考
  • golang内存分析工具

    pprof https blog csdn net weixin 40486544 article details 108402577 utm medium distribute pc relevant none task blog 2de
  • Unity粒子系统详解

    接下来的图片就是Unity2017 1 0f3 编辑器中的粒子系统模块 了解粒子系统 必须先了解每一个属性都代表了什么 之后才能根据这些原理来调整出自己满意的效果 主面板ParticleSystem Duration 粒子发射周期 如图的意
  • 互联网公司数据产品经理和数据分析师,主要有什么区别?

    数据产品经理和数据分析师 是目前互联网公司的热门职位 它跟数据分析师的职责有重叠的部分 不同的地方是这个职位关注的点是数据分析的产品化 这是普通互联网公司数据产品经理的日常 那数据产品经理跟互联网公司里的产品经理有什么区别呢 在大的互联网公
  • mysql+'@'%_mysql忘记登录的人:命令拒绝用户”@’%’

    跑步秀表示我以具有数据库所有权限的用户身份登录 跑步表状态 导致错误 并且错误不显示我已登录的用户名 就好像对于这个命令 mysql忘记了我是谁 其他select语句工作正常 有人可以解释一下吗怎么修 谢谢 Welcome to the M
  • HUAWEI+Eudemon1000E+防火墙+典型配置案例

    当使用consol口登入Eudemon1000E 防火墙时 如果登入失败退出可能会被锁定 提示 User interface con0 is locked 锁定的时间默认是10分钟 可以通过对con0 配置修改锁定值 设置串口console
  • 解决java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()

    最近在整理Android开发过程中的一些错误 话不多说 直接上错误 错误原因是自己想在网络请求成功后 弹出一个Toast提醒 但由于程序在主线程中创建handler后会创建一个looper对象 而子线程却不会 那什么时候需要looper L
  • 飞桨AI课程干货--带你开启新世界的大门!

    笔者近期体验了免费的 百度深度学习7日打卡第六期 Python小白逆袭大神 训练营 课程每天都有对应的直播 由中科院团队负责教学 每天有对应的作业贯穿其中 带你全程体验百度AI开放平台 AI Studio 飞桨PaddlePaddle Ea
  • SQL视图View的总结和使用

    实际工作当中 数据交互查询返回结果 SQL你是没办法找其他的完美替代的 但有的时候还是会遇到一些很头痛的问题需要视图view来解决 比如以下场景 view日常使用场景 场景一 有的时候 多个表并表条件查询 尤其是好几张表那种一起查询的那种
  • JS 使用正则

    在JS中如何使用正则来校验字符串 1 使用RegExpObject test string 匹配则为true否则为false 声明一个正则对象 var a 0 9 需要注意的是 a不是字符串 而是一个对象 我们可以打印下a的构造函数 没错
  • ESP32-WROVER-E无法正常写入固件

    在之前用模块下载程序都是好的 然后突然就出现了无法下载的现象 打印了他的输出都是 rst 0x10 RTCWDT RTC RESET boot 0x13 SPI FAST FLASH BOOT invalid header 0xffffff
  • 【2023】华为OD机试真题Java-题目0219-查找充电设备组合

    非常典型的动态规划问题 package com company test import java util Arrays public class Main1 public static void main String args int
  • Matlab使用LSTM网络做classification和regression时XTrain的若干种数据结构-part I

    目前看来 Deep learning的两大用途是classification和regression 以LSTM为例 它的优势在于对时序数据 sequence data 强大的处理能力 简单来说 可以用作 1 sequence to labe
  • 浅谈C++

    重载原因 C 中的运算符重载是一种特性 允许程序员定义自定义类类型的运算符操作 通过运算符重载 可以对类对象执行类似于内置类型的操作 例如加法 减法 乘法等 运算符重载通过定义特定的成员函数或非成员函数来实现 成员函数的运算符重载为类的成员