赋予运算符具有 *** 作自定义类型数据功能
二、实质运算符重载的实质本身就是函数调用
三、重载函数的写法 函数返回值 函数名(函数参数)
函数返回值 :运算完成后的值决定的 Complex
函数名 : operator 加上重载运算符组成函数名 operator+
参数 :看运算符的 *** 作数,具体参数个数是要看你重载函数形式是什么
函数体 : 写运算符具体想要的 *** 作
以下实现自定义 复数相加的运算符。
#include五、类成员函数重载using namespace std; class complex { public: complex(int a=0,int b=0):a(a),b(b){} friend complex operator+(complex a, complex b); void print() { cout << a << "t" << b; } protected: int a; int b; }; complex operator+(complex one, complex two) { return complex(one.a + two.a, one.b + two.b); } int main() { complex one(1, 2); complex two(2, 3); //隐式调用 complex three; three = one + two; three.print(); //显示调用 complex four; four =operator+(one,two); four.print(); }
参数个数等于 *** 作减一(对象可以表示一个数据,所以参数应该少一个)
以比较复数大小的>为例
(返回值类型可以自定义)
class complex { public: complex(int a=0,int b=0):a(a),b(b){} bool operator>(complex one) { if (this->a > one.a) return true; else if (this->a == one.a && this->b > one.b) return true; else return false; } void print() { cout << a << "t" << b; } protected: int a; int b; }; int main() { complex one(4, 2); complex two(2, 3); if (one > two) { cout << "one更大" << endl; } else cout << "233" << endl; }六、特殊运算符重载 ①流运算符重载:(string类型为何作为一个对象,可直接输出->流重载)
cin类型:istream类
cout类型:ostream类(std自带)
流运算符:<< >>
第一个版本的写法:(缺点:无法连续进行cin和cout,保持流的状态)
#includeusing namespace std; class math { public: math(int score=1,int rank=2):score(score),rank(rank) {} void print_data() { cout << score << 't' << rank << endl; } friend void operator>>(istream& in,math&wbm); friend void operator<<(ostream& out, math& wbm); protected: int score; int rank; }; void operator>>(istream& in, math&wbm) { in>>wbm.score>>wbm.rank; } void operator<<(ostream& out, math& wbm) { out< >wbm; cout << wbm; return 0; }
修改:返回一个istream类或者ostream类的对象即可。
#includeusing namespace std; class math { public: math(int score=1,int rank=2):score(score),rank(rank) {} void print_data() { cout << score << 't' << rank << endl; } friend istream& operator>>(istream& in,math&wbm); friend ostream& operator<<(ostream& out, math& wbm); protected: int score; int rank; }; istream& operator>>(istream& in, math&wbm) { in>>wbm.score>>wbm.rank; return in; } ostream& operator<<(ostream& out, math& wbm) { out< >wbm>>num; cout << wbm< 至此,我们综合写一个complex复数的加减。
#includeusing namespace std; class complex { public: complex(int a = 1,int b = 2):a(a),b(b){} friend ostream& operator<<(ostream& out, complex& wbm); protected: int a;//石不 int b;//虚部 }; ostream& operator<<(ostream& out, complex& wbm) { out << '(' << wbm.a << '+' << wbm.b << 'i' << ')' ; return out; } int main() { complex wbm; cout << wbm; return 0; } 对运算符“<<”重载后,在程序中用“<<”不仅能输出标准类型数据,而且可以输出用户自己定义的类对象。用“cout<
②自增自减++和--运算符的重载
下面对怎样实现运算符重载作一些说明。程序中重载了运算符“<<”,运算符重载函数中的形参output是ostream类对象的引用,形参名output是用户任意起的。分析main函数最后第二行:
cout<运算符“<<”的左面是cout,前面已提到cout是ostream类对象。“<<”的右面是c3,它是Complex类对象。由于已将运算符“<<”的重载函数声明为Complex类的友元函数,编译系统把“cout< operator<<(cout, c3)
即以cout和c3作为实参,调用下面的operator<<函数:
ostream& operator<<(ostream& output,Complex& c)
{
output<<"("<return output;
}
调用函数时,形参output成为cout的引用,形参c成为c3的引用。因此调用函数的过程相当于执行:cout<<″(″<请注意,上一行中的“<<”是C++预定义的流插入符,因为它右侧的操作数是字符串常量和double类型数据。执行cout语句输出复数形式的信息。然后执行return语句。
思考,return output的作用是什么?回答是能连续向输出流插入信息。output是ostream类的对象,它是实参cout的引用,也就是cout通过传送地址给output,使它们二者共享同一段存储单元,或者说output是cout的别名。因此,return output就是return cout,将输出流cout的现状返回,即保留输出流的现状。
现在可以理解了为什么C++规定运算符“<<”重载函数的第一个参数和函数的类型都必须是ostream类型的引用,就是为了返回cout的当前值以便连续输出。
请读者注意区分什么情况下的“<<”是标准类型数据的流插入符,什么情况下的“<<”是重载的流插入符。如
cout<<c3<<5<有下划线的是调用重载的流插入符,后面两个“<<”不是重载的流插入符,因为它的右侧不是Complex类对象而是标准类型的数据,是用预定义的流插入符处理的。 关键在于解决“前置和后置的问题”->引入一个int无用参数,表示后增
注意:通常return 一个匿名对象,注意若用引用,必须类型一致,即需要写const 或者写成右值引用的形式
#include③文本重载:using namespace std; class wbm { public: wbm(int age = 18,int rank=1):age(age),rank(rank){} wbm operator++(int)//后增重载 { int num=age; age++; return wbm(num,rank);//匿名函数,参数类型为const 若为函数引用,需要改函数类型为const常量 //以上代码等同于一行 return wbm(age++,rank); } wbm operator++()//不带int(无用参数)则为前置加加 { return wbm(++age, rank); } void printdata() { cout << age << 't' << rank << endl; } protected: int age; int rank; }; int main() { wbm bb;//默认18 1 wbm temp; temp = bb++; //temp age=18 bb age=19 temp.printdata(); bb.printdata(); temp = ++bb;//temp 20 bb 20 temp.printdata(); bb.printdata(); return 0; } zb小技巧:
#include
this_thread::sleep_for(3s);
此处的3s就是文本重载
自写:
打印出7200s
七、类的对象的隐式转换#include八、重载的综合案例 ①手写一个数组vector(待定。。。)using namespace std; class boy { public: boy(int age=1):age(age){ } operator int() { return age; } protected: int age; }; int main() { boy wbm; int wbmAge = wbm; cout << wbmAge << endl; return 0; } ②封装一个新的int类型
#include#include using namespace std; class Int { public: Int(int num):num(num){} string tostr() { return to_string(num); } Int operator+(const Int& one)//拜托一定注意是const 记得取引用& 为了防止拷贝本的产生 { return Int(this->num + one.num); } //由于当用到-号的时候不知道是this->num在前还是在后,所以,我们这里采用友元的写法确认前后关系 friend Int operator-(const Int& one,const Int& two) { return Int(one.num + two.num); } Int operator+=(const Int& a) { return Int(this->num + a.num); } Int operator++(int)//后置 { return Int(this->num++); } Int operator++() { return Int(++(this->num)); } Int operator&(const Int& a) { return Int(this->num & a.num); } bool operator!() { return !(this->num); } Int operator-() { return Int(-this->num); } friend istream& operator>>(istream& in,Int& a)//流重载要写友元 { in >> a.num; return in; } friend ostream& operator<<(ostream& out, Int& b) { out << b.num; return out; } int* operator&() { return (&(this->num)); } bool operator<(const Int& a) { return (this->num < a.num); } protected: int num; }; int main() { Int a(1); Int b(2); Int sum = a + b; Int fub = -a; int* p = &a; cout << p << endl; cout << (a < b) << endl; cout << a << endl; cout << fub << endl; cout << sum << endl; return 0; } ③重载[ ] 取值
#includeusing namespace std; //重载[]取值! class vector { public: vector(int size):size(size) { base = new int[size] {0}; } int& operator[](int num)//引用 { return base[num]; } protected: int* base; int size; }; int main() { vector wbm(3); for (int i = 0; i < 3; i++) { cin >> wbm[i];//注意这里cin的细节,cin要对一个变量进行输入,所以上面在对[]进行重载的时候必须返回的int& 是一个变量 } for (int i = 0; i < 3; i++) { cout << wbm[i]; } return 0; } ④重载()运算符 函数指针
#includeusing namespace std; class Function { typedef void (*PF)(); public: Function(PF pf):pf(pf){} void operator()() { pf(); } protected: PF pf; }; void print() { cout << 12222 << endl; } int main() { Function pf(print); pf();//通过一个类的对象来调用一个函数 return 0; } 补充一个更加直观的例子:
#includeusing namespace std; class Function { public: void operator()() { cout << "重载()" << endl; } //仿函数:让对象模仿函数的行为 bool operator()(int a,int b) { return (a > b); } //以上两个函数就是()运算符的重载 protected: } ⑤重载—>运算符: 智能指针
#includeusing namespace std; class wbm { public: wbm(string name,int age):name(name),age(age){} int age; string name; }; class auto_pstr { public: auto_pstr(int * str):str(str){} auto_pstr(wbm* str):wbmstr(str){} int& operator*()//取引用,为了提供一个接口 { return *str; } wbm* operator->() { return wbmstr;//重载-> } ~auto_pstr()//智能指针的原因:自动释放 { if (wbmstr) { delete wbmstr; wbmstr = nullptr; } if (str) { delete str; str = nullptr; } } protected: int* str; wbm* wbmstr; }; int main() { auto_pstr pstr(new int(19)); cout << *pstr << endl;//*上面已经对*做过了重载 auto_pstr wbmstr(new wbm("jie", 19)); cout << wbmstr->name< 做过了重载 cout << wbmstr->age << endl; return 0; } 注意:流重载 只可以用友元进行重载
= () -> [ ] 仅可以采用类成员重载(->还没有参数(类成员函数的重载参数-1))
. .* ?: ::(作用域分辨符)不能被重载
课后作业:重载实战: 封装一个Array类,实现定长数组的 *** 作
#includeusing namespace std; class Array { public: Array(int cursize=0):cursize(cursize) { base = new int[cursize]{0};//初始化为0 } int& size() { return cursize; } //对[]进行重载 int& operator[](int num) { return base[num]; } //流重载 friend istream& operator>>(istream& in, Array a) { for (int i = 0; i < a.cursize; i++) { in >> a.base[i]; } return in; } friend ostream& operator<<(ostream& out, Array b) { for (int i = 0; i < b.cursize; i++) { out << b.base[i]; out << " "; } return out; } //+重载 Array operator+(Array b) { Array sum(this->cursize + b.cursize); for (int i = 0; i < this->cursize; i++) { sum.base[i] = this->base[i]; } int i = 0; for (int j= this->cursize; j < this->cursize + b.cursize; j++) { sum.base[j] = b.base[i++]; } return sum; } protected: int* base; int cursize; }; int main() { //以下测试代码要能够成功运行 Array array(4); for (int i = 0; i < array.size(); i++) { cin >> array[i]; //说明对[]进行了重载 } for (int i = 0; i < array.size(); i++) { cout << array[i]; } //实现数组的连接 Array one(3); //输入1 2 3 cin >> one; //流重载 Array two(3); //输入2 3 4 cin >> two; Array sum = one + two; //加号重载 cout << sum<< endl; //打印1 2 3 2 3 4 Array num; num = sum; cout << num << endl; return 0; } 以上代码有点问题:写了指针,没有释放,内存泄漏。写了之后发现爆了
->原因:临时变量sum二次释放!(在重载+的函数内)也就是在sum(局部)转交权给了函数后,这个函数的返回值实际上是一个指向相同地址的Array对象,但指向的地址里面的内容已经被清空,所以当再次析构会爆
一次改进:在这个sum(局部)new一个新的对象(指向一个新的地址)(占用堆区内存)
但无法释放,虽然可以运行不爆,但内存泄露了。
Array operator+(Array& b)//&防止拷贝本产生,提高效率 { Array* sum=new Array(this->cursize + b.cursize); for (int i = 0; i < this->cursize; i++) { sum->base[i] = this->base[i]; } int i = 0; for (int j= this->cursize; j < this->cursize + b.cursize; j++) { sum->base[j] = b.base[i++]; } return *sum; }所以并不太推荐这种写法。
然鹅上面的代码依旧会爆(原因:用的默认拷贝构造(浅拷贝)这里,return的时候,实际上就是相当于一个拷贝的(隐式)过程,但指向的同一块区域,故析构必会出问题->重新写一个拷贝构造函数(深)包括下面的sum=one+two也会导致相类似的问题,所以也要对=号进行一个重载)
#includeusing namespace std; class Array { public: Array(int cursize=0):cursize(cursize) { base = new int[cursize]{0};//初始化为0 } int& size() { return cursize; } //对[]进行重载 int& operator[](int num) { return base[num]; } //流重载 friend istream& operator>>(istream& in, Array& a) { for (int i = 0; i < a.cursize; i++) { in >> a.base[i]; } return in; } friend ostream& operator<<(ostream& out, Array& b) { for (int i = 0; i < b.cursize; i++) { out << b.base[i]; out << " "; } return out; } //+重载 Array& operator+(Array& b)//&防止拷贝本产生,提高效率 { Array* sum=new Array(this->cursize + b.cursize); for (int i = 0; i < this->cursize; i++) { sum->base[i] = this->base[i]; } int i = 0; for (int j= this->cursize; j < this->cursize + b.cursize; j++) { sum->base[j] = b.base[i++]; } return *sum; } void operator=(Array& a) { this->cursize = a.cursize; this->base = new int[a.cursize]; for (int i = 0; i < this->cursize; i++) { this->base[i] = a.base[i]; } } Array(Array& a) { this->cursize = a.cursize; this->base = new int[a.cursize]; for (int i = 0; i < this->cursize; i++) { this->base[i] = a.base[i]; } } ~Array() { delete[]base; } protected: int* base; int cursize; }; int main() { //以下测试代码要能够成功运行 Array array(4); for (int i = 0; i < array.size(); i++) { cin >> array[i]; //说明对[]进行了重载 } for (int i = 0; i < array.size(); i++) { cout << array[i]; } //实现数组的连接 Array one(3); //输入1 2 3 cin >> one; //流重载 Array two(3); //输入2 3 4 cin >> two; Array sum = one + two; //加号重载 cout << sum<< endl; //打印1 2 3 2 3 4 Array num; num = sum; cout << num << endl; return 0; } 此为调试最终版,但仍会有内存的泄露问题(建议用智能指针写。)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)