第8周-任务1-方案3-复数类中运算符重载(与实数运算)

  接:第8周-任务1-方案2-复数类中运算符重载(非成员函数实现)

  本文在方案2的基础上,扩展+、-、*、/运算符的功能,使之能与double型数据进行运算。设Complex c; double d; c?d和d?c的结果为“将d视为实部为d的复数同c运算”的结果(其中?为+、-、*、/之一)。另外,再定义一目运算符 -,-c相当于0-c。

【讲解视频】

【参考解答】

  在下面的解答中,我将所有二目运算符的重载定义为友元函数,一目运算符重载为成员函数,这是惯用的做法。

#include <iostream>
using namespace std;
class Complex
{
public:
	Complex(){real=0;imag=0;}
	Complex(double r,double i){real=r;imag=i;}
	Complex operator-();
	friend Complex operator+(Complex &c1, Complex &c2);
	friend Complex operator+(double d1, Complex &c2);
	friend Complex operator+(Complex &c1, double d2);
	friend Complex operator-(Complex &c1, Complex &c2);
	friend Complex operator-(double d1, Complex &c2);
	friend Complex operator-(Complex &c1, double d2);
	friend Complex operator*(Complex &c1, Complex &c2);
	friend Complex operator*(double d1, Complex &c2);
	friend Complex operator*(Complex &c1, double d2);
	friend Complex operator/(Complex &c1, Complex &c2);
	friend Complex operator/(double d1, Complex &c2);
	friend Complex operator/(Complex &c1, double d2);
	void display();
private:
	double real;
	double imag;
};

Complex Complex::operator-()
{
	return(0-*this);
}

//复数相加:(a+bi)+(c+di)=(a+c)+(b+d)i.
Complex operator+(Complex &c1, Complex &c2)
{
	Complex c;
	c.real=c1.real+c2.real;
	c.imag=c1.imag+c2.imag;
	return c;
}
Complex operator+(double d1, Complex &c2)
{
	Complex c(d1,0);
	return c+c2; //按运算法则计算的确可以,但充分利用已经定义好的代码,既省人力,也避免引入新的错误,但可能机器的效率会不佳
}
Complex operator+(Complex &c1, double d2)
{
	Complex c(d2,0);
	return c1+c;
}
//复数相减:(a+bi)-(c+di)=(a-c)+(b-d)i.
Complex operator-(Complex &c1, Complex &c2)
{
	Complex c;
	c.real=c1.real-c2.real;
	c.imag=c1.imag-c2.imag;
	return c;
}
Complex operator-(double d1, Complex &c2)
{
	Complex c(d1,0);
	return c-c2;
}
Complex operator-(Complex &c1, double d2)
{
	Complex c(d2,0);
	return c1-c;
}

//复数相乘:(a+bi)(c+di)=(ac-bd)+(bc+ad)i.
Complex operator*(Complex &c1, Complex &c2)
{
	Complex c;
	c.real=c1.real*c2.real-c1.imag*c2.imag;
	c.imag=c1.imag*c2.real+c1.real*c2.imag;
	return c;
}
Complex operator*(double d1, Complex &c2)
{
	Complex c(d1,0);
	return c*c2;
}
Complex operator*(Complex &c1, double d2)
{
	Complex c(d2,0);
	return c1*c;
}

//复数相除:(a+bi)/(c+di)=(ac+bd)/(c^2+d^2) +(bc-ad)/(c^2+d^2)i
Complex operator/(Complex &c1, Complex &c2)
{
	Complex c;
	c.real=(c1.real*c2.real+c1.imag*c2.imag)/(c2.real*c2.real+c2.imag*c2.imag);
	c.imag=(c1.imag*c2.real-c1.real*c2.imag)/(c2.real*c2.real+c2.imag*c2.imag);
	return c;
}
Complex operator/(double d1, Complex &c2)
{
	Complex c(d1,0);
	return c/c2;
}
Complex operator/(Complex &c1, double d2)
{
	Complex c(d2,0);
	return c1/c;
}

void Complex::display()
{
	cout<<"("<<real<<","<<imag<<"i)"<<endl;
}

int main()
{
	Complex c1(3,4),c2(5,-10),c3;
	double d=11;
	cout<<"c1="; c1.display();
	cout<<"c2="; c2.display();
	cout<<"d="<<d<<endl;
	cout<<"-c1=";(-c1).display();
	c3=c1+c2;
	cout<<"c1+c2="; c3.display();
	cout<<"c1+d=";	(c1+d).display();
	cout<<"d+c1=";	(d+c1).display();
	c3=c1-c2;
	cout<<"c1-c2="; c3.display();
	cout<<"c1-d=";	(c1-d).display();
	cout<<"d-c1=";	(d-c1).display();
	c3=c1*c2;
	cout<<"c1*c2="; c3.display();
	cout<<"c1*d=";	(c1*d).display();
	cout<<"d*c1=";	(d*c1).display();
	c3=c1/c2;
	cout<<"c1/c2=";	c3.display();
	cout<<"c1/d=";	(c1/d).display();
	cout<<"d/c1=";	(d/c1).display();

	system("pause");
	return 0;
}

【关于参数类型及限定词选择的一点讨论】

  我在空间中,看到了leihengxin发的一个贴子:《链接

  他给的程序是:

#include<iostream>
using namespace std;
class Complex
{
public:
	Complex(){real=0;imag=0;}
	Complex(double r,double i){real=r;imag=i;}
	friend Complex operator+(Complex &c1,Complex &c2);
	friend Complex operator + (Complex &c, double &d);
	friend Complex operator + (double &d, Complex &c);
	friend void display(Complex &c2);
private:
	double real;
	double imag;
};

//复数相加:(a+bi)+(c+di)=(a+c)+(b+d)i.
Complex operator+(Complex &c1,Complex &c2)
{
	Complex c;
	c.real=c1.real+c2.real;
	c.imag=c1.imag+c2.imag;
	return c;
}
Complex operator+(Complex &c,double  &d)
{
	return Complex(c.real+d, c.imag);
}
Complex operator+(double &d, Complex &c)
{
	return Complex(c.real+d, c.imag);
}

void display(Complex &c)
{
	cout<<"("<<c.real<<","<<c.imag<<"i)"<<endl;
}   

int main()
{
	Complex c1(3,4),c2(5,-10),c3,c4;
	double dd=4.32;
	c3=c1+3.14;
	cout<<"c1+3.14=";
	display(c3);
	c4=3.14+c1;
	cout<<"3.14+c1=";
	display(c4);
	system("pause");
	return 0;
}

  在这个程序中,第X,X行将参数d声明为引用:double &d。这是一个不错的考虑,但也带来了错误,原因在于编译器不能将c1+3.14中3.14这个double型常量与double型引用变量&d匹配起来。至于为什么,请感兴趣的同学能够找资料做些进一步的解释,写在本文的评论中。

  如何解决?

  有网友给出了一种解决方案:

  (1)函数参数不要用引用

friend Complex operator + (Complex &c1, doubled);
friend Complex operator + (double d,Complex &c1);

这种方法可行。但d用成引用类型并无不妥。保持d为引用,还有两种改法:

  (2)在main()函数中,声明一个double型变量,如double dd=3.14,然后再执行c3=c1+dd。这能使显然这种方法给重载的运算符的使用套上了枷锁(只能加变量不能加常量,要让复数加一个常量,必然先要赋值给一个变量),并不可取。

  (3)将运算符重载函数的参数加上const限定词,为double型的引用const double &d

friend Complex operator + (Complex &c,constdouble &d);
friend Complex operator+ (const double&d, Complex &c);

  这样,调用c1+3.14时,编译器顺利地将3.14解释为double型常量。使用这种方案,支持复数加double型变量,而且,当d为变量,在函数中是不允许修改d值,这与“执行加法”的要求是一致的,我们不希望完成操作了,加数也发生了变化。甚至在这里,将参数c也声明为const更好,即

friend Complex operator + (const Complex &c, const double &d);
friend Complex operator+ (const double&d, const Complex &c);

  所以,在以上的三种方案中,倾向于用第三种方案。

  再讨论一个钻牛角尖的问题,如果采用第三种方案,既能加常量,也能加变量,而且当加变量时,变量值在函数体内是可变的(当然这种设计并不可取),该如何去做。我们可以继续重载operate+函数,一共需要4个版本的定义了:

    friend Complex operator + (const Complex &c, constdouble &d);
    friend Complex operator+ (const double&d, const Complex &c);
    friend Complex operator + (Complex &c, double &d);
    friend Complex operator+ (double &d, Complex &c);

  加与不加const是有区别的,编译器认可这是不同的函数,在参数是非const变量时,爱改就改吧。

时间: 2024-09-16 20:49:01

第8周-任务1-方案3-复数类中运算符重载(与实数运算)的相关文章

第8周-任务1-方案2-复数类中运算符重载(非成员函数实现)

接:第8周-任务1-方案1-复数类中运算符重载(成员函数实现) 本文用方案二求解:用类的友元函数,而不是成员函数,完成上面提及的运算符的重载: [讲解视频] [参考解答] #include <iostream> using namespace std; class Complex { public: Complex(){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} friend Complex operator+(Comp

C++第8周(春)项目1 实现复数类中的运算符重载

课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 [项目1]实现复数类中的运算符重载(1)请用类的成员函数,定义复数类重载运算符+.-.*./,使之能用于复数的加减乘除 class Complex { public: Complex(){real=0;imag=0;} Complex(double r,double i){real=r; imag=i;} Complex operator+(C

第9周-任务2-Time类中运算符重载

[题目]接第8周任务2,定义Time类中的<<和>>运算符重载,实现时间的输入输出,改造原程序中对运算结果显示方式,使程序读起来更自然. [参考解答] #include <iostream> using namespace std; class CTime { private: unsigned short int hour; // 时 unsigned short int minute; // 分 unsigned short int second; // 秒 pub

第9周-任务3-分数类中运算符重载

[题目]接第8周任务3,定义分数类中<<和>>运算符重载,实现时间的输入输出,改造原程序中对运算结果显示方式,使程序读起来更自然. [参考解答] #include <iostream> using namespace std; class CFraction { private: int nume; // 分子 int deno; // 分母 public: CFraction(int nu=0,int de=1):nume(nu),deno(de){} void si

C++第9周项目1 - 实现复数类中的运算符重载

课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565,本周题目链接:http://blog.csdn.net/sxhelijian/article/details/8841620 [项目1-Complex类]接第8周项目1,定义Complex类中的<<和>>运算符的重载,实现输入和输出,改造原程序中对运算结果显示方式,使程序读起来更自然. 参考解答:(在VS2008中调试通过,CodeBlocks中有编译错误,

第九周-任务1-Complex类中运算符的重载

[题目]接第8周任务1,定义Complex类中的<<和>>运算符的重载,实现输入和输出,改造原程序中对运算结果显示方式,使程序读起来更自然. [参考解答] #include <iostream> using namespace std; class Complex { public: Complex(){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} Complex operator-(); //实现

《C++语言基础》实践参考——复数类中的运算符重载(续)

返回:贺老师课程教学链接 项目要求 [项目1-复数类中的运算符重载(续)]在复数类中的运算符重载基础上(1)再定义一目运算符 -,-c相当于0-c.(2)定义Complex类中的<<和>>运算符的重载,实现输入和输出,改造原程序中对运算结果显示方式,使程序读起来更自然.[参考解答] #include <iostream> using namespace std; class Complex { public: Complex() { real=0; imag=0; }

C++第8周(春)项目2 实现Time类中的运算符重载

课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 [项目2-Time类中的运算符重载]实现Time类中的运算符重载 class CTime { private: unsigned short int hour; // 时 unsigned short int minute; // 分 unsigned short int second; // 秒 public: CTime(int h=0,i

C02-程序设计基础提高班(C++)第11周上机任务-运算符重载

第11周:阅读教材第10章(p314-346),掌握用运算符重载解决问题,完成第11周上机任务: (回到C02-程序设计基础提高班(C++)学习安排) [任务1]实现复数类中的运算符重载定义一个复数类重载运算符+.-.*./,使之能用于复数的加减乘除.(1)方案一:请用类的成员函数完成运算符的重载: class Complex { public: Complex(){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} Comple