C++面向对象程序设计 - 重载运算符进一步讨论

          函数重载就是对一个已有的函数赋予新的含义,使之实现新的功能。因此一个函数名就可以用来代表不同功能的函数,也就是一名多用。运算符也可以重载,即运算符重载(operator overloading)。

一、非成员、非友元的重载运算符

        在C++中,我们可以通过重载运算符来使得自定义类型(比如复数类)可以像内置类型一样使用运算符。

题目:定义一个复数类Complex,重载运算符“+”,使之能用于复数的加法运算。将运算符函数重载为非成员、非友元的普通函数。编写程序,求两个复数之和。

解析:此题中要定义一个非成员函数、非友元的重载运算符函数来实现两个复数之和,则在重载函数中无法调用Complex类中的私有数据成员,则需要在Complex类中定义set和get函数来实现复数相加。代码如下:

#include <iostream>
using namespace std;
class Complex{private:double real;double imag;public:// 无参构造函数Complex(){this->real = 0;this->imag = 0;}// 有参构造函数Complex(double real, double imag): real(real), imag(imag){}// 定义修改数据成员的函数void setReal(int real){this->real = real;}void setImag(int imag){this->imag = imag;}// 定义获取数据成员的函数int getReal(){return real;}int getImag(){return imag;}// 定义显示结果函数void display(){cout <<"(" <<real <<"," <<imag <<"i)" <<endl;}
};
// 定义重载运算符函数
Complex operator +(Complex& c1, Complex& c2){return Complex(c1.getReal() + c2.getReal(), c1.getImag() + c2.getImag());
}
int main(){// 实例Complex对象c1,c2,c3;Complex c1(10.0, 5.0), c2(20.0, 30.0), c3;// 通过重载运算符函数 计算C1 + C2得到C3c3 = c1 + c2;// 显示结果c1.display();c2.display();c3.display();return 0;
}

        运行结果如下图:

二、实现+、-、*、/运算符重载

        在C++中,要将运算符重载为类的成员函数,通常对于二元运算符(如+、-、*、/),需要有一个操作数是当前类的对象(作为隐式的this指针),而另一个操作数作为函数的参数。对于一元运算符(如取反-),则不需要参数。

题目:定义一个复数类Complex,重载运算符“+”、“-”、“*”、“/”,使之能用于复数加、减、乘、除。运算符重载函数作为Complex类的成员函数。编程序,分别求两个复数之和、差、积和商。

解析:此题中是将重载运算符作为Complex类的成员函数,它接受一个const Complex&类型的参数,并返回一个新的Complex对象,这是两个复数的运算结果。例如当你使用+运算符来加两个Complex对象时,实际上是在调用这个成员函数。代码如下:

#include <iostream>
using namespace std;
class Complex{private:double real;double imag;public:// 无参构造函数Complex(){this->real = 0;this->imag = 0;}// 有参构造函数Complex(double real, double imag): real(real), imag(imag){}// 定义重载运算符 + 成员函数Complex operator + (const Complex& c){return Complex(real + c.real, imag + c.imag);}// 定义重载运算符 - 成员函数Complex operator - (const Complex& c){return Complex(real - c.real, imag - c.imag);}// 定义重载运算符 * 成员函数Complex operator * (const Complex& c){double realPart = real * c.real - imag * c.imag;double imagPart = real * c.imag + imag * c.real;return Complex(realPart, imagPart);}// 定义重载运算符 / 成员函数Complex operator / (const Complex& c){double denominator = real * c.real + imag * c.imag;double realPart = real * c.real - imag * c.imag;double imagPart = real * c.imag + imag * c.real;return Complex(realPart/denominator, imagPart/denominator);}// 定义显示结果函数void display(const char *oper){cout <<oper <<": (" <<real <<"," <<imag <<"i)" <<endl;}
};
int main(){// 实例Complex对象c1,c2,c3,c4,c5,c6;Complex c1(10.0, 5.0), c2(20.0, 30.0), c3, c4, c5, c6;// 开始计算c3 = c1 + c2;		// +c4 = c1 - c2;		// -c5 = c1 * c2;		// *c6 = c1 / c2;		// ///显示结果c1.display("c1");c2.display("c2");cout <<endl <<"Result of operation:" <<endl;c3.display("+");c4.display("-");c5.display("*");c6.display("/");return 0;
}

        运行结果如下图:

三、任意组合进行运算

题目:定义一个复数类Complex,重载运算符“+”,使之能用于复数的加法运算。参加运算的两个运算量可以都是类对象,也可以其中有一个是整数,顺序任意。例如:c1 + c2,i + c1,c1 + i均合法(设i为整数,c1,c2为复数)。编程序,分别求两个复数之和、整数和复数之和。

解析:c1+c2为对象+对象,使用“二”中的运算符符重载成员函数即可;i+c1为整形+对象,其中i非Complex对象,所以需要通过运算符重载友元函数来实现; c1+i为对象 + 整形,则需要在Complex类内中定义重载运算符+的成员函数来实现。所以此题中需要对运算符+重载三次,代码如下:

#include <iostream>
using namespace std;
class Complex{private:double real;double imag;public:// 定义有参构造函数,并添加默认值Complex(double real = 0.0, double imag = 0.0): real(real), imag(imag){}// 声明重载运算符 + 的友元函数(用于整形 + 对象)friend Complex operator + (double, const Complex&);// 定义重载运算符 + 成员函数(用于对象 + 对象)Complex operator + (const Complex& c) const{return Complex(real + c.real, imag + c.imag);}// 定义重载运算符 + 成员函数(用于 对象 + 整形)Complex operator +(int val) const{return Complex(real + val, imag);}// 定义显示结果函数void display(const char* p){cout <<p  <<": (" <<real <<"," <<imag <<"i)" <<endl;}
};
// 定义重载运算符 + 友元函数
Complex operator + (double val, const Complex& c2){return Complex(val + c2.real, c2.imag);
}
int main(){// 实例Complex对象c1,c2,c3,c4,c5Complex c1(10.0, 5.0), c2(20.0, 30.0), c3, c4, c5;int i = 10;// 计算结果c3 = c1 + c2;c4 = i + c1;c5 = c1 + i;// 显示结果c1.display("c1");c2.display("c2");cout <<endl <<"Result of operation:" <<endl;// 显示运算结果c3.display("c3");c4.display("c4");c5.display("c5");return 0;
}

        这里使用常引用(const reference)和常成员函数(const member function)是为了提供几个关键的好处。

常引用(如const Complex& c):

  • 避免数据拷贝:通过传递引用而不是值,可以避免复制对象,这在处理大型对象时尤其重要,因为它可以提高性能。
  • 保护数据不被修改:const修饰符确保传递给函数的对象不会被函数内的代码修改。这对于那些只需要读取数据而不修改数据的函数来说是非常重要的。

常成员函数:

        在成员函数后添加const关键字意味着这个成员函数不会修改调用它的对象的任何成员变量(除非它们被声明为mutable)。这有助于确保对象的封装性,并且让调用者知道这个函数是安全的,不会意外地改变对象的状态。

总之,使用常引用和常成员函数是C++中常见的做法,它们有助于确保数据的安全性和一致性,同时提高代码的可读性和可维护性。

思考:在上篇文章中讲过不同数据类型间的转换,此题是否也可以运用到此方法。完成此项工作,则需要定义Complex类的友元函数来实现,使用之能处理对象+对象的运算,而i变量不管在运算符左侧,还是右侧,通过隐式转换为Complex(i);当然Complex类中必须要定义只带一个参数的转换构造函数。代码如下:

#include <iostream>
using namespace std;
class Complex{private:double real;double imag;public:Complex(){this->real = 0.0;this->imag = 0.0;}// 定义一个有参构造函数Complex(double real): real(real){}// 定义有参构造函数,并添加默认值Complex(double real, double imag): real(real), imag(imag){}// 声明重载运算符 + 的友元函数friend Complex operator + (const Complex&, const Complex&);// 定义显示结果函数void display(const char* p){cout <<p  <<": (" <<real <<"," <<imag <<"i)" <<endl;}
};
// 定义重载运算符 + 的友元函数
Complex operator + (const Complex& c1, const Complex& c2){return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
int main(){// 实例Complex对象c1,c2,c3,c4,c5Complex c1(10.0, 5.0), c2(20.0, 30.0), c3, c4, c5;int i = 10;// 计算结果c3 = c1 + c2;		// c1 + c2c4 = i + c1;		// Complex(i) + c1,隐式转换c5 = c1 + i;		// c1 + Complex(i), 隐式转换// 显示结果c1.display("c1");c2.display("c2");cout <<endl <<"Result of operation:" <<endl;// 显示运算结果c3.display("c3");c4.display("c4");c5.display("c5");return 0;
}

        运算结果如下:

四、重载运算符>>和<<

题目:有两个矩阵a和b,均为2行3列。求两个矩阵之和。重载运算符“+”,使之能用于矩阵相加(c = a + b)。重载流插入运算符“<<”和流提取运算符“>>”,使之能用于该矩阵的输入和输出。

解析:定义一个Matrix类:

  • 构造函数Matrix(int rows, int cols)初始化一个指定行数和列数的矩阵。
  • 重载的operator+函数用于矩阵相加。
  • 重载的operator<<函数用于输出矩阵的内容到输出流(通常是std::cout)。
  • 重载的operator>>函数用于从输入流(通常是std::cin)读取矩阵的内容。

运算符<<和>>重置函数形式:

istream & operator >> (istream &, 自定义类 &);

ostream & operator << (ostream &, 自定义类 &);

        代码如下:

#include <iostream>
using namespace std;
class Matrix{private:int rows;int cols;public:// 无参构造函数Matrix(){this->rows = 0;this->cols = 0;}// 有参构造函数Matrix(int r, int c): rows(r), cols(c){}// 定义重载运算符 + 成员函数Matrix operator +(const Matrix& m){return Matrix(rows + m.rows, cols + m.cols);}// 声明重载的operator<<函数用于输出矩阵的内容到输出流friend ostream& operator <<(ostream&, Matrix&);// 声明重载的operator>>函数用于从输入流friend istream& operator >>(istream&, Matrix&);
};
// 定义重载的operator<<函数用于输出矩阵的内容到输出流ostream& operator <<(ostream& os, Matrix& m){cout <<m.cols <<" columns and " <<m.rows <<" rows of the matrix" <<endl;for(int i = 0; i < m.rows; i++){for(int j = 0; j < m.cols; j++){os <<"*";	}	os <<endl;}return os;}// 定义重载的operator>>函数用于从输入流istream& operator >>(istream& is, Matrix& m){cout <<"Enter the columns and rows of the matrix (e.g. 2*3):" <<endl;is >>m.rows >>m.cols;return is;}int main(){// 定义矩阵对象a,b,cMatrix a, b, c;// 输入矩阵a、b的行和列cin >>a;cin >>b;// 计算求和,得到c(通过重载运算符+)c = a + b;// 输出结果cout <<c;return 0;
}

        运行结果如下图:

五、类型转换函数

题目:处理一个复数与一个double数相加的运算,结果存放在一个double型的变量d1中,输出d1的值,再以复数形式输出此值。定义Complex(复数)类,在成员函数中包含重载类型转换运算符。

解析:为了处理一个复数与一个double数相加,并将结果存放在一个double型的变量中,首先需要定义一个Complex类来表示复数。这个类应该包含两个数据成员来分别表示复数的实部和虚部。然后需要重载类型转换运算符,以便可以将Complex对象转换为double类型。最后将double结果放到Complex类中以复数形式输出。代码如下:

#include <iostream>
using namespace std;
class Complex{private:double real;double imag;public:// 无参构造函数Complex(){this->real = 0;this->imag = 0;}// 有参构造函数Complex(double real, double imag): real(real), imag(imag){}// 重载类型转换运算符operator double() const{return real;}// 定义显示结果函数void display(){cout <<"(" <<real <<"," <<imag <<"i)" <<endl;}
};
int main(){// 实例Complex对象c1,c2Complex c1(10.0, 5.0);double num, num2;// num = 30.5 + c1;num2 = c1 + 10.5;// 以复数形式输出Complex(num, 0.0).display();Complex(num2, 0.0).display();return 0;
}

        运行结果如下:

六、类对象之间转换

题目:定义一个Teacher(教师)类和一个Student(学生)类,二者有一部分数据成员是相同的,例如num(号码)、name(姓名)、sex(性别)。编写程序,将一个Student对象(学生)转换为Teacher(教师)类,只将以上3个相同的数据成员移植过去。可以设想为:一位学生大学毕业了,留校担任教师,他原有的部分数据对现在的教师身份来说扔然是有用的,应当保留并成员其教师的一部分。

解析:实现这个功能,需要在Teacher类中定义一个构造函数,该构造函数接受一个Student对象作为参数,并从中提取num、name和sex数据成员的值来初始化Teacher对象。通常被称为“拷贝构造函数”,实际上它不是从同一类型的对象拷贝数据,而是从另一个类型的对象拷贝数据。

代码如下:

#include <iostream>
#include <string>
using namespace std;
// 定义学生类
class Student{private:int num;string name;int age;public:// 定义有参构造函数Student(int num, string name, int age): num(num), name(name), age(age){}// 定义外部获取私有数据成员int getNum() const { return num; }string getName() const{ return name; }int getAge() const{ return age; }
};
// 定义教师类
class Teacher{private:int num;string name;int age;public:// 定义复制构造函数Teacher(const Student& s): num(s.getNum()), name(s.getName()), age(s.getAge()){}// 定义显示结果函数void display(){cout <<"num:" <<num <<endl;cout <<"name:" <<name <<endl;cout <<"age:" <<age <<endl;}
};
int main(){Student stu(1001, "Tom", 15);// 将学生类数据拷贝给教师类Teacher t(stu);// 输出教师信息t.display();return 0;
}

        运行结果如下:

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

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

相关文章

STM32F103学习笔记 | 1.Keil5详细安装教程

Keil5详细安装教程 https://www.keil.com/download/product/

使用API有效率地管理Dynadot域名,自查账户信息

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

大型组织企业 怎么实现便捷高效的跨地区文件交换?

大型组织企业&#xff0c;尤其是银行、邮政、大型集团、跨国企业等&#xff0c;都会存在多个分支机构&#xff0c;会面临跨地区文件交换的场景和需求。 跨地区文件交换可能会遇到以下问题&#xff1a; 1、网络带宽限制&#xff1a;跨国或跨大陆传输时&#xff0c;网络带宽可能…

CC攻击频发,企业如何做好网络安全,该怎么防护能免遭CC攻击?

在当前网络现状下&#xff0c;随着信息技术的飞速发展&#xff0c;网络攻击手段也愈发多样化和复杂化。其中&#xff0c;CC攻击作为一种针对Web应用层的拒绝服务攻击&#xff0c;其危害日益凸显&#xff0c;对企业和个人造成了严重的威胁。下面我们就从多个角度详细分享关于CC攻…

LyricWikia, 一个让你玩物丧志的Python库

文章目录 LyricWikia: Python的歌词查找库背景LyricWikia是什么&#xff1f;安装简单的库函数使用方法场景示例搜索并显示歌词获取歌手的热门歌曲搜索并下载歌词 常见问题和解决方案总结 LyricWikia: Python的歌词查找库 背景 LyricWikia是一个用于查找和获取歌曲歌词的Python…

【项目实战】基于高并发服务器的搜索引擎

【项目实战】基于高并发服务器的搜索引擎 目录 【项目实战】基于高并发服务器的搜索引擎搜索引擎部分代码index.htmlindex.hpplog.hppparser.cc&#xff08;用于对网页的html文件切分且存储索引关系&#xff09;searcher.hpputil.hpphttp_server.cc&#xff08;用于启动服务器和…

【Linux的git操作】

Linux学习笔记---010 Linux的git操作1、什么是gitee2、git 准备工作2.1、查看是否安装了 git 版本工具2.2、安装 git 工具/更新成最新版本2.3、在gitee上创建远程仓库&#xff08;略&#xff09;2.4、提交file的初始化操作 3、git的“三板斧”3.1、add3.2、commit3.3、push3.4、…

Amazon云计算AWS之[2]弹性计算云EC2

文章目录 说明EC2基本架构Amazon机器映象&#xff08;AMI&#xff09;实例&#xff08;Instance&#xff09;弹性块存储&#xff08;EBS&#xff09; EC2关键技术地理区域和可用区域EC2通信机制弹性负载均衡监控服务自动缩放服务管理控制台 EC2安全及容错机制EC2弹性IP地址 说明…

Pyside6:多行按钮点击判断序号

在Pyside开发过程中会遇到这么个问题&#xff1a;当多个按钮在很多行中&#xff0c;需要在点击槽函数中确认按钮的行。 普通的按钮点击信号如下&#xff1a; clicked() 该信号并未有任何参数&#xff0c;无法得到有效的信息&#xff0c;那么如何完成点击哪个确定是哪个按钮呢…

计算机系列之校验码

6、校验码 1、码距 码距&#xff1a;就单个编码 A: 00 而言&#xff0c;其码距为 1&#xff0c;因为其只需要改变一位就变成另一个编码。**在两个编码中&#xff0c;从 A 码到 B 码转换所需要改变的位数成为码距&#xff0c;**如 A: 00 要转换为 B: 11&#xff0c;码距为2。一…

WIFI信号状态信息 CSI 特征提取篇之活动片段提取上(五)

在之前的数据处理环节中&#xff0c;用CSI Tool收集到的原始数据信号&#xff0c;经历了数据解析、降噪、插值的处理步骤&#xff0c;变成了干净、完整的信号片段&#xff0c;这是后续做更进一步分析的基础。 在开始阅读本篇博客前&#xff0c;需要说明两个重要的点&#xff1…

使用ClickHouse、Grafana和WarpStream规模化的解决可预测成本的日志留存

本文字数&#xff1a;13234&#xff1b;估计阅读时间&#xff1a;34 分钟 作者&#xff1a;Dale McDiarmid & Ryadh Dahimene 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 简介 在生产环境中操作任何复杂的技术堆栈而没有适当…

2024年低碳技术与污染控制技术国际学术会议(ICLCTPCT 2024)

2024年低碳技术与污染控制技术国际学术会议(ICLCTPCT 2024) 2024 International Conference on Low carbon technology and pollution control technology 一、【会议简介】 2024年低碳技术与污染控制技术国际学术会议&#xff0c;是交流科研成果的绝佳平台。 这次会议将汇集世…

如何利用美国站群服务器实现有效的SEO优化策略?

如何利用美国站群服务器实现有效的SEO优化策略? 在当今数字化时代&#xff0c;SEO优化对于网站的可见性和吸引力至关重要。站群服务器作为一种有效的SEO策略&#xff0c;可以通过多个相关联的网站在不同服务器上的部署&#xff0c;增强网站的权威性和链接多样性。尤其是在利用…

vector的使用(部分接口)

1.vector的使用 1.1vector的定义 (constructor)构造函数声明接口说明vector()无参构造vector (const vector& x)拷贝构造 1.2vector iterator 的使用 iterator的使用接口说明begin end获取第一个数据位置的iterator/const_iterator&#xff0c; 获取最后一个数据的下一个位…

【做算法学数据结构】二叉树的层序遍历【二叉树】

文章目录 题目二叉树二叉树描述二叉树的java描述和前序遍历、后序遍历、中序遍历 题解总结以及二叉树应用场景 题目 给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历…

力扣HOT100 - 98. 验证二叉搜索树

解题思路&#xff1a; class Solution {public boolean isValidBST(TreeNode root) {return recur(root,Long.MIN_VALUE,Long.MAX_VALUE);}public boolean recur(TreeNode root,long lower,long upper){if(rootnull) return true;if(root.val<lower||root.val>upper) re…

python爬虫之爬取携程景点评价(5)

一、景点部分评价爬取 【携程攻略】携程旅游攻略,自助游,自驾游,出游,自由行攻略指南 (ctrip.com) import requests from bs4 import BeautifulSoupif __name__ __main__:url https://m.ctrip.com/webapp/you/commentWeb/commentList?seo0&businessId22176&busines…

爬虫零基础学习,第一天,安装环境,requests库常用命令的讲解

Python爬虫 爬虫学习思路 URL内容获取&#xff0c;requests的基本常用语法 import requests # 先向目标网站发送请求 url "http://www.baidu.com" r requests.get(url) # 可以用看一下访问码返回值是不是200&#xff0c;若是200则表示访问成功 print(r.status_…

Web3与物联网:探索区块链如何驱动智能设备的未来

引言 在数字化快速发展的时代&#xff0c;Web3技术和物联网&#xff08;IoT&#xff09;都成为了前沿技术的代表。两者的结合正逐渐展现出无限的可能性&#xff0c;尤其是在智能设备和数据安全方面。本文将深入探讨Web3如何与物联网相结合&#xff0c;以及这种结合对未来智能设…