C++学习笔记08
复习:
运算符重载:
编译器把运算符当作函数
全局
函数名:operator 运算符
参数表:所有操作数
返回类型:合乎情理即可
成员
函数名:operator 运算符
参数表:除第一个之外的操作数,当前对象作为第一个操作数
返回类型:合乎情理即可
编译器会尝试这两种形式([]()=->type只当成员函数),如果两种都有或者都没有,编译失败。每个运算符函数只允许有其中一种形式。
operator type()不写返回类型却胜写返回类型,因为函数名里面已经包含返回类型
ostream& operator<<(ostream& o,const A& x);
istream& operator>>(istream& i,A& x);
这两个只能写成非成员函数。如果需要访问对象的私有成员,就要在类里把他们声明成友元
const对象只能调用const成员函数(const在参数表后)
const成员函数里的this是const A* const,而普通成员函数的this是A* const
const对象中的mutable修饰的数据成员允许修改
双目运算符重载:
a+b: a.operator+(b) operator+(a,b)
单目运算符重载:
&a: a.operator& (),operator&(a)
指针
const int* p;//p指向const int
int const* p;//p指向const int
int* const p;//p本身是const
const int* const p;//p本身是const而且指向const int
运算符重载
->返回内部某个结构变量的地址,编译器通过这个地址执行真正的->操作访问里面的成员
#include<iostream> using namespace std; struct POINT{ int x; int y; }; class Pos{ POINT p; public: Pos(int x=0,int y=0){p.x = x,p.y=y;} void move(int cx,int cy){p.x+=cx,p.y+=cy;} void moveto(int x,int y){p.x = x,p.y=y;} POINT* operator->(){return &p;} }; int main() { Pos a(20,80); cout<<a->x<<","<<a->y<<endl; a.move(30,-10); cout<<a->x<<","<<a->y<<endl; system("pause"); }
new/delete重载负责内存的分配和释放,编译器会在内存分配之后调用构造函数,内存释放之前调用析构函数,有[]和没有[]是不同的运算符
#include<iostream> #include<cstdio> using namespace std; class A{ int data; public: A(int d=0):data(d){cout<<"A("<<data<<")"<<endl;} ~A(){cout<<"~A()"<<data<<endl;} void* operator new(size_t bytes){ cout<<"bytes="<<bytes<<endl; return malloc(bytes);} void operator delete(void* p){ cout<<"p="<<p<<endl; return free(p); } void* operator new[](size_t bytes){ cout<<"bytes="<<bytes<<endl; void* p = malloc(bytes); cout << "malloc:"<<p<<endl; return p; } void operator delete[](void* p){ cout<<"p="<<p<<endl; return free(p); } }; int main() { A* p= new A;//operator new sizeof(A) cout<<"sizeof A="<<sizeof(A)<<endl; cout<<"p="<<p<<endl; delete p;p=NULL;//operator delete(p) cout<<"-----------------------"<<endl; p = new A[3]; cout<<"p="<<p<<endl; cout<<"*p="<<*((int *)p-1)<<endl;//数组前一位存数组个数 delete[] p;p=NULL; system("pause"); }
++/--
前++前--,正常的单目运算符用法,计算结果就是变量的最新值因此可以直接拿这个对象做计算结果
成员:A& operator++(){... return *this;}
友元:friend A& operator++(A& x){... return x;}
后++后--,非正常用法,计算结果是对象的旧值,必须用临时空间来保存,不能拿对象本身作为计算记过,定义运算符函数时需要一个多余的int哑元。
成员:A operator++(int){... return old;}
友元:friend A operator++(A x,int){... return old;}
运算符重载一定要合乎情理。运算符重载是自己规定运算符对于特定类型的操作数应该如何工作,对于基本类型的运算不应该重载,不应该创造新的运算符,不应该改变操作数的个数。
有些运算符不允许重载:. , .* , ?:,::,typeid,sizeof
#include <iostream> using namespace std; class R{//分数类 int n; int d; public: friend ostream&operator<<(ostream&o,const R&x){ return o<<x.n<<"/"<<x.d; } R(int n,int d):n(n),d(d){} R& operator++(){//成员形式的前++ n+=d; return *this; } //非成员形式(友元形式)的前-- friend R& operator--(R& x){ x.n=x.n-x.d; return x; } }; int main() { R a(3,4); cout<<"a="<<a<<endl; cout<<"a="<<++ ++ a<<endl;//operator++(a),a.operator++() cout<<"a="<<-- -- a<<endl; system("pause"); }
#include<iostream> using namespace std; class R{ int n; int d; public:R(int n=0,int d=1):n(n),d(d){} friend ostream& operator<<(ostream&,const R&); R operator++(int){//返回类型不应该加引用 //虚假的形参 int 用于与前++区分,是哑元 R old = *this; n+=d; return old; } }; ostream& operator<<(ostream& o, const R& x) { return o<<x.n<<"/"<<x.d; } int main() { R a(3,5); cout<<"a++ ="<<a++<<endl; //a.operaotr(0)后++会传一个无用的参数0 cout<<"a="<<a<<endl; system("pause"); }