网站设计公司西安,wordpress 美食,网站模块分类,云开发和普通开发区别这里写目录标题 运算符重载在全局范围内重载运算符运算符重载时要遵循的规则运算符重载到底以成员函数的形式更好还是全局函数#xff08;友元函数#xff09;的形式更好重载例题#xff08;属于友元函数的 运算符重载函数#xff09; 运算符重载
运算符重载其实就是定义一… 这里写目录标题 运算符重载在全局范围内重载运算符运算符重载时要遵循的规则运算符重载到底以成员函数的形式更好还是全局函数友元函数的形式更好重载例题属于友元函数的 运算符重载函数 运算符重载
运算符重载其实就是定义一个函数在函数体内实现想要的功能当用到该运算符时编译器会自动调用这个函数。也就是说运算符重载是通过函数实现的它本质上是函数重载。
// complex类内
public://声明运算符重载complex operator(const complex A) const;//实现运算符重载
complex complex::operator(const complex A) const{complex B;B.m_real this-m_real A.m_real;B.m_imag this-m_imag A.m_imag;return B;
}运算符重载的格式为 返回值类型 operator 运算符名称 (形参表列){ //TODO: } operator是关键字专门用于定义重载运算符的函数。我们可以将operator 运算符名称这一部分看做函数名对于上面的代码函数名就是operator。
运算符重载函数除了函数名有特定的格式其它地方和普通函数并没有区别。
上面的例子中我们在 complex 类中重载了运算符该重载只对 complex 对象有效。当执行c3 c1 c2;语句时编译器检测到号左边号具有左结合性所以先检测左边是一个 complex 对象就会调用成员函数operator()也就是转换为下面的形式
c3 c1.operator(c2);c1 是要调用函数的对象c2 是函数的实参。
上面的运算符重载还可以有更加简练的定义形式
complex complex::operator(const complex A)const{return complex(this-m_real A.m_real, this-m_imag A.m_imag);
}return 语句中的complex(this-m_real A.m_real, this-m_imag A.m_imag)会创建一个临时对象这个对象没有名称是一个匿名对象。在创建临时对象过程中调用构造函数return 语句将该临时对象作为函数返回值。
在全局范围内重载运算符
运算符重载函数不仅可以作为类的成员函数还可以作为全局函数。更改上面的代码在全局范围内重载实现复数的加法运算
//在全局范围内重载
complex operator(const complex A, const complex B){complex C;C.m_real A.m_real B.m_real;C.m_imag A.m_imag B.m_imag;return C;
}当执行c3 c1 c2;语句时编译器检测到号两边都是 complex 对象就会转换为类似下面的函数调用 c3 operator(c1, c2);完整代码
#include iostream
using namespace std;class complex{
public:complex();complex(double real, double imag);
public:void display() const;//声明为友元函数friend complex operator(const complex A, const complex B);
private:double m_real;double m_imag;
};complex operator(const complex A, const complex B);complex::complex(): m_real(0.0), m_imag(0.0){ }
complex::complex(double real, double imag): m_real(real), m_imag(imag){ }
void complex::display() const{coutm_real m_imagiendl;
}//在全局范围内重载
complex operator(const complex A, const complex B){complex C;C.m_real A.m_real B.m_real;C.m_imag A.m_imag B.m_imag;return C;
}int main(){complex c1(4.3, 5.8);complex c2(2.4, 3.7);complex c3;c3 c1 c2;c3.display();return 0;
}运算符重载函数不是 complex 类的成员函数但是却用到了 complex 类的 private 成员变量所以必须在 complex 类中将该函数声明为友元函数。
运算符重载时要遵循的规则
四则运算符、-、、/、、-、、/和关系运算符、、、、、!都是数学运算符它们在实际开发中非常常见被重载的几率也很高并且有着相似的重载格式。本节以复数类 Complex 为例对它们进行重载重在演示运算符重载的语法以及规范。
#include iostream
#include cmath
using namespace std;//复数类
class Complex{
public: //构造函数Complex(double real 0.0, double imag 0.0): m_real(real), m_imag(imag){ }
public: //运算符重载//以全局函数的形式重载friend Complex operator(const Complex c1, const Complex c2);friend Complex operator-(const Complex c1, const Complex c2);friend Complex operator*(const Complex c1, const Complex c2);friend Complex operator/(const Complex c1, const Complex c2);friend bool operator(const Complex c1, const Complex c2);friend bool operator!(const Complex c1, const Complex c2);//以成员函数的形式重载Complex operator(const Complex c);Complex operator-(const Complex c);Complex operator*(const Complex c);Complex operator/(const Complex c);
public: //成员函数double real() const{ return m_real; }double imag() const{ return m_imag; }
private:double m_real; //实部double m_imag; //虚部
};//重载运算符
Complex operator(const Complex c1, const Complex c2){Complex c;c.m_real c1.m_real c2.m_real;c.m_imag c1.m_imag c2.m_imag;return c;
}
//重载-运算符
Complex operator-(const Complex c1, const Complex c2){Complex c;c.m_real c1.m_real - c2.m_real;c.m_imag c1.m_imag - c2.m_imag;return c;
}
//重载*运算符 (abi) * (cdi) (ac-bd) (bcad)i
Complex operator*(const Complex c1, const Complex c2){Complex c;c.m_real c1.m_real * c2.m_real - c1.m_imag * c2.m_imag;c.m_imag c1.m_imag * c2.m_real c1.m_real * c2.m_imag;return c;
}
//重载/运算符 (abi) / (cdi) [(acbd) / (c²d²)] [(bc-ad) / (c²d²)]i
Complex operator/(const Complex c1, const Complex c2){Complex c;c.m_real (c1.m_real*c2.m_real c1.m_imag*c2.m_imag) / (pow(c2.m_real, 2) pow(c2.m_imag, 2));c.m_imag (c1.m_imag*c2.m_real - c1.m_real*c2.m_imag) / (pow(c2.m_real, 2) pow(c2.m_imag, 2));return c;
}
//重载运算符
bool operator(const Complex c1, const Complex c2){if( c1.m_real c2.m_real c1.m_imag c2.m_imag ){return true;}else{return false;}
}
//重载!运算符
bool operator!(const Complex c1, const Complex c2){if( c1.m_real ! c2.m_real || c1.m_imag ! c2.m_imag ){return true;}else{return false;}
}//重载运算符
Complex Complex::operator(const Complex c){this-m_real c.m_real;this-m_imag c.m_imag;return *this;
}
//重载-运算符
Complex Complex::operator-(const Complex c){this-m_real - c.m_real;this-m_imag - c.m_imag;return *this;
}
//重载*运算符
Complex Complex::operator*(const Complex c){this-m_real this-m_real * c.m_real - this-m_imag * c.m_imag;this-m_imag this-m_imag * c.m_real this-m_real * c.m_imag;return *this;
}
//重载/运算符
Complex Complex::operator/(const Complex c){this-m_real (this-m_real*c.m_real this-m_imag*c.m_imag) / (pow(c.m_real, 2) pow(c.m_imag, 2));this-m_imag (this-m_imag*c.m_real - this-m_real*c.m_imag) / (pow(c.m_real, 2) pow(c.m_imag, 2));return *this;
}int main(){Complex c1(25, 35);Complex c2(10, 20);Complex c3(1, 2);Complex c4(4, 9);Complex c5(34, 6);Complex c6(80, 90);Complex c7 c1 c2;Complex c8 c1 - c2;Complex c9 c1 * c2;Complex c10 c1 / c2;coutc7 c7.real() c7.imag()iendl;coutc8 c8.real() c8.imag()iendl;coutc9 c9.real() c9.imag()iendl;coutc10 c10.real() c10.imag()iendl;c3 c1;c4 - c2;c5 * c2;c6 / c2;coutc3 c3.real() c3.imag()iendl;coutc4 c4.real() c4.imag()iendl;coutc5 c5.real() c5.imag()iendl;coutc6 c6.real() c6.imag()iendl;if(c1 c2){coutc1 c2endl;}if(c1 ! c2){coutc1 ! c2endl;}return 0;
}复数能够进行完整的四则运算但不能进行完整的关系运算我们只能判断两个复数是否相等但不能比较它们的大小所以不能对 、、、 进行重载。
需要注意的是我们以全局函数的形式重载了 、-、、/、、!以成员函数的形式重载了 、-、、/而且应该坚持这样做不能一股脑都写作成员函数或者全局函数
运算符重载到底以成员函数的形式更好还是全局函数友元函数的形式更好
C 规定箭头运算符-、下标运算符[ ]、函数调用运算符( )、赋值运算符只能以成员函数的形式重载。
1.全局函数的形式重载 、-、*、/、、!
解释一C 只会对成员函数的参数进行类型转换而不会对调用成员函数的对象进行类型转换
假设 在成员函数中 对进行重载
public:Complex operator(const Complex c1)const;//类外实现
Complex Complex::operator(const Complex c1)const {Complex c3;c3.m_real this-m_real c1.m_real;c3.m_imag this-m_imag c1.m_imag;return c3;Complex c1(25, 35);Complex c2 c1 15.6;cout c2 c2.real() c2.imag() i endl;// Complex c3 15.6 c1;// cout c3 c3.real() c3.imag() i endl;上述代码执行Complex c2 c1 15.6;编译器检测到号左边号具有左结合性所以先检测左边是一个 complex 对象就会调用成员函数operator()。检测到15.6是一个double。于是自动调用Complex(double real)这个转换构造函数。最后执行成功。
但是如果执行Complex c3 15.6 c1;就会发生错误了因为 double 类型并没有以成员函数的形式重载 。
也就是说以成员函数的形式重载 只能计算c1 15.6不能计算15.6 c1。 全局函数形式重载
public:friend Complex operator(const Complex c1, const Complex c2);Complex operator(const Complex c1, const Complex c2) {Complex c;c.m_real c1.m_real c2.m_real;c.m_imag c1.m_imag c2.m_imag;return c;
}
C 只会对成员函数的参数进行类型转换而不会对调用成员函数的对象进行类型转换
解释二 若在成员函数
class Complex
{double real,imag;public:Complex(double r,double i):real(r),imag(i) { };Complex operator (double r);
};
Complex Complex::operator(double r)
{return Complex(real r,imag);
}
可以解释Complex c; c c 5,相当于 cc.operator(5) 但是不能解释c 5 c,所以将运算符重载为普通函数此时参数个数就是原生运算符的目数而不是目数减一但不能访问对象的私有成员所以要在类中将函数声明为友元函数。
class Complex
{double real,imag;public:Complex(double r,double i):real(r),imag(i) { };Complex operator (double r);friend Complex operator (double r,const Complex c);
};
Complex Complex::operator(double r,const Complex c)
{return Complex(c.real r,c.imag);
}
其实就是为了确定类型吧当参数个数为运算符目数 运算数的顺序无所谓可以匹配参数进行识别 当参数个数为运算符目数-1就麻烦了顺序匹配时ok重载的类别在前否则未重载的类别在前就无法进行运算 根据解释一虽然可以对对象进行类型转换但只能对 只会对成员函数的参数进行类型转换而不会对调用成员函数的对象进行类型转换所以 未重载的类别在前时重载的对象 即调用成员函数的对象不会进行类型转换 成员函数的形式重载 、-、*、/ 因为 符号不存在有数据类型颠倒的情况且 运算符重载的初衷是给类添加新的功能方便类的运算所以这类运算符首选用类的成员函数去重载。 参考一 参考二
重载
stopwatch stopwatch::run(){m_sec;if(m_sec 60){m_min;m_sec 0;}return *this;
}
stopwatch stopwatch::operator(){return run();
}
stopwatch stopwatch::operator(int n){stopwatch s *this;run();return s;
}上面的代码定义了一个简单的秒表类m_min 表示分钟m_sec 表示秒钟setzero() 函数用于秒表清零run() 函数是用来描述秒针前进一秒的动作接下来是三个运算符重载函数。
先来看一下 run() 函数的实现run() 函数一开始让秒针自增如果此时自增结果等于60了则应该进位分钟加1秒针置零。
operator() 函数实现自增的前置形式直接返回 run() 函数运行结果即可。
operator (int n) 函数实现自增的后置形式返回值是对象本身但是之后再次使用该对象时对象自增了所以在该函数的函数体中先将对象保存然后调用一次 run() 函数之后再将先前保存的对象返回。在这个函数中参数n是没有任何意义的它的存在只是为了区分是前置形式还是后置形式。
自减运算符的重载与上面类似这里不再赘述。
例题属于友元函数的 运算符重载函数 因为是双目运算符但是函数里只传了一个参数就必然使用了this指针那就肯定不是友元函数了 因为友元函数没有当前对象因此要定义单目运算符就需要单参函数要定义双目运算符就需要双参函数 定义后置“或后置“–运算是特例它们是单目运算符但需要两个形参头一个形参是作用对象后一个是int形参 用友元函数可以定义成员函数不能实现的运算例如一些双目运算符右操作数是本类对象而左操作数不是本类对象 成员函数体中当前对象作为一个操作数无形参形式可以定义单目运算符
作者Geng1995 链接https://www.nowcoder.com/exam/test/72063274/submission