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

本文详细介绍了C++中如何通过重载运算符实现复数类的加法运算,以及如何在Teacher和Student类间进行数据成员的迁移。包括非成员函数、成员函数的重载,不同类型间运算符的处理,如整数与复数的结合,以及类对象之间的转换构造函数的应用。
摘要由CSDN通过智能技术生成

          函数重载就是对一个已有的函数赋予新的含义,使之实现新的功能。因此一个函数名就可以用来代表不同功能的函数,也就是一名多用。运算符也可以重载,即运算符重载(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得到C3
	c3 = 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,c5
	Complex 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,c5
	Complex c1(10.0, 5.0), c2(20.0, 30.0), c3, c4, c5;
	int i = 10;
	// 计算结果
	c3 = c1 + c2;		// c1 + c2
	c4 = 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,c
	Matrix 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,c2
	Complex 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;
}

        运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

觉醒法师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值