Lesson 20 运算符重载

来源:互联网 发布:linux测试dns解析命令 编辑:程序博客网 时间:2024/06/08 09:55

多态:同一种形为,不同的对象得到不同的结果;(按这里的定义来看,不一定是函数,可以是运算符)  //运算符应该是重载,多态才是覆盖,重载不能算 是多态;上面的辩证法可能 有问题??  

静态多态(运算符重载,函数重载)

一、运算符重载

Complex obj1,obj2,obj3;

obj1 = 3;

obj3 = obj2;

obj3 = obj1 + obj2;

cout<< obj1<<obj2<<endl;

上面的运算符,默认情况下是无法实现的,因此需要为自定义的类实现自己的运算符;

运算符重载:对已有的功能赋以其另一种功能,以适用于不同的数据类型;

重载不能修改优先级和结合性!重载的功能应与原功能相似;

不可以重载的运算符有: .    .*    ::   ?:


运算符重载可以通过定义类的成员函数或是友元函数实现 

成员函数重载运算符:

返回类型 类名::operator运算符(形参列表)

{

}


<span style="font-size:24px;">complex operator+(const complex& m) const;  </span>
<span style="font-size:24px;"><span style="color:#ff0000;">//这里用2个const 是因为外面的const修饰thist,并不是说m不可以改变</span>complex a(1,2);complex b(2,3);complex c = a +b; /// 运算符左操作符是调用函数的对象,右操作数是参数  a.operator+(b); </span>

///  使用成员函数重载运算符,左操作数要求是类本身对象,而右操作数可以为其它类型 如上面参数为int

//    这时可以再次重载,参数传int ,实现 b = a + 3;



显然,成员函数无法实现 b =  3 + a


友元全局函数重载运算符

friend 返回值类型 operator运算符(形参列表) // 二元操作要两个形参,一元操作为空形参列表

{

}


friend complex operator+(const Complex &a, const Complex &b);   

// 用友元的意义是为了能访问类的私有成员,如果私有成员都有接口,那可以不用友元 


b =  3 + a是可以用全局函数实现!


建议:二元操作用友元全局函数实现; 如果第一个操作数要求是本类对象,推荐用成员函数,如果第一                 个数肯定不是本类对象,推荐用友元函数实现


特定的运算符:

1. 只能用成员函数实现的运算符:(第一个操作数一定要是本类对象)

= ,  (),  [ ],  -> :如= 如果用a = b ,则本类对象是a,b = a 的本类对象是b;a 与b 的类型可能不同;



2. 只能使用友元函数实现的:(第一个操作数一定不是本类对象)


>> , << (输入输出)


二、常用运算符重载

单目:++, --   //推荐使用成员函数

++a;   

成员函数:

 Complex & operator++()   //  返回必须是本类对象的引用,返回引用则可以作左值: ++a = 3;   // a = 3;

{

++m_real;

++m_imag;

return *this;   // 左值看成返回本身

}

a++;   

 Complex operator++ (int)  // int 没有任何意义

{

Complex temp(*this);

++m_real;

++m_imag;

return temp;

}


友元全局函数:

Complex &operator--(Complex& a)   // --a;

{

a.m_real ++;

a.m_imag ++

return ax;

}



双目运算符:

1. >> 、<<

cout<<a;   cin>>a; 第一个操作数都不是本类对象;因此要用到友元全局函数;

cout << a << b; // 说明返回值是可以做左值的,即要返回引用ostream类型;

friend istream& operator>>(istream& in, 用户类型& obj)  // obj用&可以不用干枯析内存

{

in >> obj.x;

in >> obj.y;

return in;

}


friend ostream & operator<<(ostream& out, const 用户类型& obj)

{

out<<obj.x;

return out

}


cin>>a>>b;     //  operator>>((operator(cin,a)),b);


2. 赋值运算符重载 

// 当类要定义析构函数(指针成员被删2次)的时候要定义拷贝构造函数(深拷贝)=运算符重载

Complex& operator=(const Complex& ref);  


=运算符只能定义成成员函数重载,即即一个操作数必须为类对象;

=不定义系统会生成一个默认的,这会造成浅拷贝的问题;


在子类中要显式的调用直接基类的=运算符!!!

class A

{

int a;

};

class B:public A

{

int b;

};


B& operator=(B& ref)  // 有两部分要赋值:A类中的a,B类中的b;

{

A::operator=(ref); // 子类赋给A类

b = ref.b;

return *this;

}




com a;

com b = a; // 初始化拷贝构造函数

com c;

c = a; // =运算符重载


3. 下标运算符[ ]

TYPE & operator[ ](const int aIndex);  // TYPE存储的数据类型


重载new, delete运算符

void *类名::operator new(size_t, [arg_list]);

形参表中至少含有一个size_t的参数,且必须为第一个参数


void 类名::operator delete(void*, [arg_list]);

若有第二个参数,必须为size_t


重载类型转换运算符:

没有转换运算符重载函数,则强制类型转换只能对标准类型操作有作用!

Length obj1(1000);

double m = double(obj1);    // double m = obj1.operator double();    显示调用的结果


m = obj1;   // m = obj1.operator double();   //隐示调用


operator<强制转换的目标类型>()   // 无参数(只转换自身),无返回值

{

// 定义后,可以显式调用或是隐式调用 

}


可以通过构造函数实现类型转换:

Complex(int b);

void foo(Complex com);


int b= 5;  foo(b);  // b 被转换成了Complex类型


operator int(); // 强制类型转换

上面两个红色的过程,都完成了类型转换,同时转换会出现二义性!即foo(b);不知道调用 哪个函数完成类型转换


总结

类型重载方式:

Coordinate coo(2,3);
Complex com(1,2);
com = coo;

1. 赋值运算符重载;    com = coo;  // com.operator=(const Coordinate& coo);

2. 构造函数;  com = coo;    // 先调用Complex::Complex(const Coordinate& coo);再用赋值运算符=赋给com

3. 类型转换运算符();  com = coo;  // 在Coordinate类中实现:   operator Complex() const;  先调用Coordinate类中的类型转换运算符,再调用Complex类的赋值运算符



#ifndef TEST#define  TEST#include <iostream>#include <string>using namespace std;class B;class A;extern ostream& operator<<(ostream& in,const A&a);extern ostream& operator<<(ostream& in,const B&a);class A{public:int x;int y;friend ostream& operator<<(ostream& out,const A&a);A():x(5),y(10){};//A(B& b);   // 构造函数完成类型转换A& operator=(const B& b);  // 赋值运算符完成类型转换};class B{public:string str1;string str2;B():str1("123.5"),str2("55.5"){};friend ostream& operator<<(ostream& out,const B&a);operator A();};#endif

#include "testmain.h"#include <iostream>#include <string>using namespace std;// 强制类型转换ostream& operator<<(ostream& out, A&a){out << "A的值为:" << a.x<<" "<<a.y;return out;}ostream& operator<<(ostream& out,const B&a){out<<"B: "<<a.str1<<" "<<a.str2;return out;}/*A::A(B& b){cout<<"开始调用构造函数转换B->A:"<<b<<endl;x = atoi(b.str1.c_str());y = atoi(b.str2.c_str());cout<<"构造函数转换成功后:"<<x<<" "<<y<<endl;}*/A& A::operator=(const B& b){cout<<"开始调用赋值运算符转换B->A:"<<b<<endl;x = atoi(b.str1.c_str()) + 1;y = atoi(b.str2.c_str()) + 1;cout<<"赋值运算符转换成功后:"<<x<<" "<<y<<endl;return *this;}B::operator A(){cout<<"开始调用强制类型转换运算符转换B->A"<<endl;A a;a.x = atoi(str1.c_str()) + 10;a.y = atoi(str2.c_str()) + 10;cout<<"强制类型转换运算符转换成功后:"<<a.x<<" "<<a.y<<endl;return a;}int main(){A a;B b;cout<<b<<endl;cout<<a<<endl;a = b;cout<<"_____________________"<<endl;B c;a = A(c);cout<<a<<endl;}





0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 吃了不新鲜的鱼怎么办 生的猪肉有点臭怎么办? 猪肉馅不新鲜了怎么办 买的肉有点臭了怎么办 炸的东西不脆了怎么办 油炸东西回软了怎么办 吃石斑鱼蛋吐了怎么办 家里的烟筒堵了怎么办 脖子上长鸡皮肤怎么办 铁板烤蔬菜粘锅怎么办 残余尿量300ml怎么办 肌肉拉伤怎么办恢复快小腿 睡觉把背扭了怎么办 后背一侧扭筋了怎么办 背部的筋扭到了怎么办 跳绳跳得膝盖疼怎么办 跑步小腿变粗了怎么办 一蹲下膝盖就响怎么办 做深蹲时膝盖总是吱吱响怎么办 爬山爬的膝盖疼怎么办 膝盖一吹风就疼怎么办 走路太多膝盖腿疼怎么办 膝盖一着凉就痛怎么办 月子里脚受凉了怎么办 膝关节受凉少量积液发胀怎么办 刮痧后吹空调了怎么办 200斤胖子膝盖痛怎么办 风扇吹的腿疼怎么办 膝盖受凉但不疼怎么办 刮痧后洗了澡怎么办 刮痧后喝了啤酒怎么办 艾灸后吃水果了怎么办 刮痧后能洗澡了怎么办 膝盖筋扭了肿了怎么办 骑行之后膝盖疼怎么办 膝盖软骨磨没了怎么办 腿上膝盖长骨刺怎么办 打羽毛球后膝盖疼怎么办 打完羽毛球膝盖疼怎么办 骑动感单车后膝盖痛怎么办 踩完动感单车右膝盖痛怎么办