Complex复数类
运算符重载的方法是定义一个重载运算符的函数,使指定的运算符可以实现在函数中指定的新的功能。
重载运算符的函数一般格式如下:
函数类型 operator 运算符名 (形参列表)
{
对运算符重载的处理
}
函数名由 operator 和运算符组成。
例:
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b);/*有参构造*/
/*负号运算符重载*/
Complex operator - ();
};
/*负号运算符重载*/
Complex Complex::operator - ()
{
Complex temp;
temp.real = -real;
temp.imag = -imag;
return temp;
}
直接调用重载的运算符
Complex Z1 { 1,2 };
Z2 = Z1.operator -(); // Z2 = -1 -2i
隐式调用重载的运算符
Complex Z{ 1,2 };
Z2 = -Z1; // Z2 = -1 -2i
对运算符重载的函数有两种处理方式:
=
、下标运算符[]
、函数调用运算符()
、成员访问箭头运算符->
必须作为成员函数重载。通常情况下,我们把算术和关系运算符定义成非成员函数以允许对左侧或右侧的运算对象进行转换。
因为这些运算符一般不需要改变运算对象的状态,所以形参都是 const 引用。
以加号运算符为例:
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b);/*有参构造*/
/*加号运算符重载*/
friend Complex operator + (const Complex& Z1 ,const Complex& Z2);
};
/*加号运算符重载*/
Complex operator + (const Complex& Z1, const Complex& Z2)
{
Complex temp;
temp.real = Z1.real + Z2.real;
temp.imag = Z1.imag + Z2.imag;
return temp;
}
算术运算符通常会计算它的两个运算对象并得到一个新值,这个值有别于任意一个运算对象,常常位于一个局部变量之内,操作完成后返回该局部变量的副本作为其结果。
应当比较对象的每一个数据成员,只有当所有对应的成员都相等时才认为两个对象相等。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
/*相等运算符重载*/
friend bool operator == (const Complex& Z1,const Complex & Z2);
/*不相等运算符重载*/
friend bool operator != (const Complex& Z1,const Complex& Z2);
};
/*相等运算符重载*/
bool operator == (const Complex& Z1, const Complex& Z2)
{
if (Z1.real == Z2.real && Z1.imag == Z2.imag)
return true;
else
return false;
}
/*不相等运算符重载*/
bool operator != (const Complex& Z1, const Complex& Z2)
{
if (Z1.real == Z2.real && Z1.imag == Z2.imag)
return false;
else
return true;
}
另一个例子:比较两个盒子的大小。
#include
using namespace std;
class Box {
private:
int length; //长度
int width; //宽度
int height; //高度
public:
Box() = default;
Box(int H, int W, int L) : height{ H }, width{ W }, length{ L } {}
int Volume() const //求盒子体积
{
return length * width * height;
}
friend bool operator == (const Box& B1, const Box& B2)
{
if (B1.Volume() == B2.Volume())
return true;
else
return false;
}
friend bool operator != (const Box& B1, const Box& B2)
{
if (B1.Volume() != B2.Volume())
return true;
else
return false;
}
friend bool operator < (const Box& B1, const Box& B2)
{
if (B1.Volume() < B2.Volume())
return true;
else
return false;
}
friend bool operator > (const Box& B1, const Box& B2)
{
if (B1.Volume() > B2.Volume())
return true;
else
return false;
}
};
int main(void)
{
Box B1{ 1,2,3 };
Box B2{ 1,2,4 };
if (B1 == B2)
cout << "两个盒子一样大" << endl;
else
{
if (B1 < B2)
cout << "B1盒子小" << endl;
else
cout << "B2盒子小" << endl;
}
return 0;
}
复合赋值运算符应为类的成员函数。
复合赋值运算符返回其左侧运算对象的引用。
以+=
运算符为例:
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
Complex& operator += (const Complex& Z2); /*+= 运算符重载*/
};
/*+= 运算符重载*/
Complex& Complex::operator += (const Complex& Z2)
{
real += Z2.real;
imag += Z2.imag;
return *this;
}
自增\自减运算符应作为成员函数重载。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
Complex & operator ++(); /*前置自增运算符重载*/
};
/*前置自增运算符重载*/
Complex & Complex::operator ++()
{
real += 1;
imag += 1;
return *this;
}
为了与内置版本保持一致,前置运算符应该返回递增或递减后对象的引用。
为区分前置版本和后置版本,后置版本接受一个额外的(不被使用的)int 类型的形参。
当我们使用后置运算符时,编译器为这个形参提供一个值为 0 的实参。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
Complex operator ++(int); /*后置自增运算符重载*/
};
/*后置自增运算符重载*/
Complex Complex::operator ++(int)
{
Complex temp; //递增前记录原值
temp.real = real;
temp.imag = imag;
real += 1;
imag += 1;
return temp;
}
为了与内置版本保持一致,后置运算符应该返回对象的原值(递增或递减之前的值),返回的形式是一个值而非引用。
重载输入\输出运算符必须是非成员函数。
通常情况下,输出运算符的第一个形参是一个 ostream 对象的引用。
第二个形参一般来说是一个 const 对象引用。
operator <<
一般要返回它的 ostream 形参的引用。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
/*重载输出运算符*/
friend ostream& operator << (ostream& output,const Complex& Z);
};
/*重载输出运算符*/
ostream & operator << (ostream& output,const Complex& Z)
{
output << Z.real <<" + "<< Z.imag << 'i';
return output;
}
通常情况下,输入运算符的第一个形参是一个 ostream 对象的引用。
第二个形参是将要读入到的非 const 对象的引用。
operator >>
通常会返回它的 istream 的引用。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
/*重载输入运算符*/
friend istream& operator >> (istream& input,const Complex& Z);
};
/*重载输入运算符*/
istream & operator >> (istream& input,const Complex& Z)
{
input >> Z.real >> Z.imag;
return input;
}
下标运算符必须是成员函数。
为了与下标的原始定义兼容,下标运算符通常以所访问元素的引用作为返回值。
class MyString
{
private:
char* str = nullptr;
unsigned int MaxSize = 0;
public:
MyString(); /*默认构造函数*/
MyString(const char* S);/*构造函数,写入字符串*/
/*下标运算符重载*/
char& operator [] (unsigned int i);
};
/*下标运算符重载*/
char& MyString::operator [] (unsigned int i)
{
return str[i];
}
如果一个类包含下标运算符,则它通常会定义两个版本:一个返回普通引用,另一个是类的常量成员并且返回常量引用。
函数调用运算符必须是成员函数。
一个类可以定义多个不同版本的调用运算符,相互之间应该在参数数量或类型上有所区别。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
/*函数调用运算符重载*/
Complex & operator() (double a, double b);
};
/*函数调用运算符重载*/
Complex& Complex::operator() (double a, double b) //修改实部和虚部的值。
{
real = a;
imag = b;
return *this;
}
可以象使用函数一样使用对象:
Complex Z; //默认构造
Z(2,3); // 函数调用运算符重载
类型转换运算符(conversion operator)是类的一种特殊成员函数,它负责将一个类类型的值转换成其他类型。
类型转换函数的一般形式如下所示:
operator type() const;
其中,type 表示某种类型。
类型转换运算符可以面向任意类型(除了void之外)进行定义,只要该类型能作为函数的返回类型。
因此,我们不允许转换成数组或者函数类型,但允许转换成指针或者引用类型。
类型转换运算符既没有显式的返回类型,也没有形参,而且必须定义成类的成员函数。
类型转换运算符通常不应该改变待转换对象的内容,因此,类型转换运算符一般被定义成 const 成员。
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
/*类型转换运算符重载*/
operator int() const; //将复数类型转换为整型数
};
/*类型转换运算符重载*/
Complex::operator int() const
{
return real;
}
隐式类型转换
Complex Z{2,3};
int a = Z; // a = 2
unsigned int b = Z //也可以执行,a = 2
强制类型转换
Complex Z{2,3};
cout << (int)Z <<endl; //输出2
cout << (unsigned int)Z <<endl; //也能输出2
C++11新标准引入了显式的类型转换运算符(explicitconversion operator)
class Complex
{
private:
double real = 0; //复数的实部
double imag = 0; //复数的虚部
public:
Complex() = default; /*无参构造*/
Complex(double a, double b); /*有参构造*/
/*类型转换运算符重载*/
explicit operator int() const; //将复数类型转换为整型数
};
/*类型转换运算符重载*/
Complex::operator int() const
{
return real;
}
当类型转换运算符是显式的时,必须通过显式的强制类型转换才可以执行类型转换。
Complex Z{2,3};
cout << (int)Z <<endl; //只能强制类型转换,输出2
但是当表达式出现在下列位置时,显式的类型转换将被隐式地执行:
!
、逻辑或运算符||
、逻辑与运算符&&
的运算对象。?:
的条件表达式。