320 likes | 476 Views
第八章 运算符重载. 用户定义类型用运算符表示操作. 8.1 运算符重载 运算符 —— 一种函数;对于类对象,用户可重新定义运算符函数。 class Complex { private: double rpart; double ipart; public:
E N D
第八章 运算符重载 用户定义类型用运算符表示操作
8.1 运算符重载 运算符——一种函数;对于类对象,用户可重新定义运算符函数。 class Complex { private: double rpart; double ipart; public: Complex ( ) { rpart=ipart=0.0; } Complex(double rp, double ip) { rpart=rp; ipart=ip; } Complex add(const Complex &com) { Complex temp; temp.rpart=com.rpart+rpart; temp.ipart=com.ip+ipart; return temp; } };
希望c=a+b; a.operator(b) 赋值运算符一般用预定义的 Complex a(10,7), b(3,5); Complex c=a.add(b); 复数加法运算重载符函数: class Complex { //…… public: Complex operator+(Complex &com) { Complex temp(rpart+com.rpart, ipart+com.ipart); return temp; } //…… }; 公有成员函数 Complex a(10,7), b(3,5), c; c=a+b;
单目无参数 双目一个参数 (a.operator-( )).operator+(b) 单目运算符重载: Complex Complex:: operator - ( ) { Complex temp; temp.rpart=-rpart; temp.ipart)=-ipart; return temp; } Complex c=-a+b; 不能重载的运算符:. , * , ::, ?, sizeof 重载应注意的问题: 1、优先级和结合顺序不变 2、不能改变目数 3、类外定义至少有一个相应类的参数
外部函数,若写为: X operator +(int i1,int i2) 内部类型,用户不能改变 operator+(x2, x3); class x { public: int i; }; X operator+(const X& x1, const X& x2) { X temp; temp.i=x1.i+x2.i; return temp; } 运算符成员函数——调用成员函数的对象隐式成为表达式的第一个运算数 外部运算符函数——其第一个参数直接对应表达式的第一个运算数; x1=x2+x3;
aa.operator@(bb) operator@(aa) operator@(aa, bb) aa.operator@( ) operator(aa, int) aa.operator( int ) 4、双目运算符@:成员函数只带一个参数;外部函数带两个参数 aa@bb aa@bb 5、单目前缀运算符@:成员函数不带参;外部函数带一个参数 @aa @aa 6、单目后缀运算符@:成员函数带一个int参数;外部函数带二个参数 aa@ aa@ 7、只能重载已有的运算符,不能创造新的
8、成员和外部运算符函数可重载(多个同名运算符函数)8、成员和外部运算符函数可重载(多个同名运算符函数) class x { public: double operator+(double) { //…… } double operator+(int) { //…… } }; float operator+(X, int) { //…… } X x1, x2, x3; x2+3.0; x2+3;
9、编译器预定义了“=”, “&”, “,(顺序)”, 三种运算符,不必重载可直接使用 class x { //…… private: void operator= (const X&); void operator& ( ); void operator, (const X&); //…… }; void f(X a, X b) { a=b; X *p=&a; } 说明为私有限制对它们的使用
b.operator(10.0) 10.0.operator(b) 8.2 算术运算符、赋值运算符和逻辑运算符的重载 8.2.1 重载算术运算符 class Complex { //…… public: Complex operator+(double) { //…… } //…… }; Complex a, b; a=b+10.0; a=10.0+b;
解决此问题——非成员函数重载: Complex operator+(double d, const Complex &com) { Complex temp; temp.rpart=d+rpart; temp.ipart=com.ipart; return temp; } 问题?——解决方法?
用于Complex的其它算术运算符重载: class Complex { //…… friend Complex operator *(double, Complex com); public: Complex operator*(double d) { //…… } //…… }; Comple operator *(double d, Complex com) { //…… } Complex a, b, c; a=3*b; a=b+c*3*5;
8.2.2 重载赋值运算符 编译器缺省的赋值运算符是逐位把源对象拷贝到目标对象。 Complex c1, c2; c1=c2; 类Cmessage的问题: #include<iostream.h> extern “C” { #include<string.h> }
class CMessage { private: char *buffer; public: CMessage( ) { buffer=new char(‘\0’); } ~CMessage( ) { delete [ ] buffer; } void Display( ) { cout<<buffer<<endl; } void Set(char *string) { delete [ ] buffer; buffer= new char[strlen(string)+1]; strcpy(buffer, string); } }; CMessage c1, c2; c1=c2; c2.Set(“newstring”); 解决方法——赋值运算符重载 c1.buffer c1.buffer c1.buffer c2.buffer c2.buffer c2.buffer
class CMessage { //…… public: void operator=(const CMessage& Message) { delete [ ] buffer; buffer= new char[strlen(Message.buffer)+1]; strcpy(buffer, Message.buffer); } //…… }; void main( ) { CMessage c1; c1.Set(“initial c1 message”); Message1.Display( ); CMessage c2; c2.Set(“initial c2 message”); c2.Display( ); c1=c2; c1.Display( ); } c1.buffer c1.buffer Initial c2 message c2.buffer c2.buffer
注意:=运算符重载必须用成员函数,不能非成员友元形式;注意:=运算符重载必须用成员函数,不能非成员友元形式; 连串赋值要返回对象的引用 Cmessage& CMessage::operator=(const CMessage& Message) { delete [ ] buffer; buffer= new char[strlen(Message.buffer)+1]; strcpy(buffer, Message.buffer); return *this; } void main( ) { CMessage Message1; CMessage Message2; CMessage Message3; Message1=Message2=Message3; } 问题 : Cmessage& CMessage::operator=(const CMessage& Message) { if( &Message==this) return *this; delete [ ] buffer; buffer= new char[strlen(Message.buffer)+1]; strcpy(buffer, Message.buffer); return *this; }
复制构造函数,初始化对象时调用 8.2.3 复制构造函数(带引用此类型的单参数的构造函数) class x { //…… public: X( ) { //…… }; X(X& xx) { //…… } //…… }; X x1; X x2(x1); X x3=x1; 若未定义,编译器生成缺省的复制构造函数(逐位拷贝)。 除此之外,下两种情况编译器自动调用复制构造函数: 1、类对象作参数传递; 2、返回一个类对象。 Complex operator+(Complex com1, Complex com2) { return Complex(com1.rpart+com2.rpart, com1.ipart+com2.ipart); } 等价,用x1初始化x2和x3,=并不调用赋值运算符
8.2.4 重载逻辑运算符 class Complex { public: int operator==(const Complex &c) { return (rpart==c.rpart) && (ipart=c.ipart); } int operator==(const double &d) { return (rpart==d) && (ipart==0); } friend int operator ==(const double &d, const Complex &com); //…… }; int operator ==(const double &d, const Complex &com) { return (com.rpart==d) && (ipart==0); } Complex c1, c2; //…… if(c1==c2) c1=c1+c2; else if(c1==3) c1=c2; //……
8.3 用户定义的转换 8.3.1 转换构造函数 带一个参数的构造函数,参数不是该类型的引用,而是其他类型。 别的类型 这个类的类型 Complex:: Complex(const double &d) { rpart=d; ipart=0.0; } class Complex { friend int operator >(const Complex &c1, const Complex &c2); //…… }; int operator >(const Complex &c1, const Complex &c2) { return sqrt(c1.rpart*c1.rpart+c1.ipart*c1.ipart) > sqrt(c2.rpart*c2.rpart+c2.ipart*c2.ipart); } 注意:多种类型进行混合运算的运算符成员函数一般采用外部友员函数的形式。 其他用到转换构造函数的地方: Complex f( ) { return 1.0; }
类型 8.3.2转换运算符 类对象类型(X) 别的类型(T) 转换运算符(成员函数)无参数、无返回值 X:: operator T( ) { //…… } class integer { int i; public: integer(int a) { i=a; } operator int( ) { return i; }; integer i1(10), i2(20); int a=i1; i1=a; i2=10+i1*2 可采用强制(显式)类型转换形式: int i; integer ir(10); i=int(ir); ir=integer(i);
8.3.3二义性 同时定义转换运算符和转换构造函数: class X { int i; public: friend X operator+(const X&, const X&); X(int ii) { i=ii; } operator int( ) { return i; } }; X operator +(const X& x1, const X& x2) { return X(x1.i+x2.i); } X x1(10); int i=x1+12; i=12+x1;
8.5 重载增量和减量运算符 class integer { int i; public: integer( int ii) { i=ii; } integer operator++( ) { ++i; return *this; } integer operator++(int) { i++; return *this; } }; integer a(1), b(1); b=a++; b=++a; integer integer:: operator++( ) { integer temp=*this; ++i; return temp; }
数组运算结果 下标 8.6 重载下标运算符 数组名[下标]:双目运算符。 注意:下标运算符函数不能用外部函数定义,只能非静态成员函数 一般形式:T1 T::operator[ ](T2); class ainteger { int *a; int sz; public: ainteger( int size) { sz=size; a=new int[size]; } int & operator[ ](int i ) { if(i<0 || i>=sz) { cout<<“error”<<endl; exit(1); } return a[i]; } ~ainteger ( ) { delete [ ]a; } }; ainteger ai(10); ai[2]=3; int i=ai[2]; ai.operator[](2) 返回ai::a[2]的引用
举例:文件数组 class FilrRef { private: class File &f; char buf[1]; unsigned long ix; public: FilrRef( File &ff, unsigned long i):f(ff), ix(i) { } FileRef & operator=(char c) operator char( ); }; class File { friend class FileRef; public: File(const char *name) { fd=open(name, O_RDWR|O_CREAT,0664); } ~File( ) { close(fd); } FileRef operator[ ](unsigned long ix) { return FileRef(*this,ix); } private: int fd; };
FileRef& FileRef:: operator=(char) { lseek(f.fd, ix, 0); write(f.fd, &c, 1); return *this; ) FileRef:: operator char( ) { lseek(f.fd, ix, 0); read(f.fd, buf, 1); return buf[0]; ) int main( ) { File foo(“foo”); foo[5]=‘5’; foo[10]=‘1’; char c=foo[5]; cout<<“c=“<<c<<endl; ) foo.operator[ ](5)产生FileRef的temp temp.operator=(‘5’)执行写操作 foo.operator[ ](5)产生FileRef的temp 调用FileRef中的转换运算符执行读操作
举例:非整型数组下标(通过某个对象能唯一地确定另一个对象)举例:非整型数组下标(通过某个对象能唯一地确定另一个对象) struct pair { char *name; int val; }; class assoc { pair *vec; int max; int free; assoc(const assoc &); assoc & operator=(const assoc &); public: assoc(int); int & operator[ ](const char*); void print_all( ); }; int & assoc::operator[ ](const char* p) { register pair* pp; for(pp=&vec[free-1]; vec<=pp; pp--) if(strcmp(p, pp->name)==0) return pp->val; if(free==max) { pair * nvec=new pair[max*2]; for(int i=0; i<max; i++) nvec[i]=vec[i]; delete [ ]vec; vec=nvec; max=2*max; } vec free max
assoc vec(512); //…… cout<<vec[“string”]<<endl; vec[“string”]=12; pp=&vec[free++]; pp->name=new char[strlen(p)+1]; strcpy(pp->name, p); pp->val=0; return pp->val; } assoc::assoc(int ) { max=(s<16)? 16: s; free=0; vec=new pai[max]; } void assoc::print_all( ) { for(int i=0; i<free; i++) cout<<vec[i].name<<“:”<<vec[i].val<<endl; } void main( ) { const MAX=256; char buf[MAX]; assoc vec(512); while(cin>>buf) vec[buf]++; vec.print_all( ); } 输入:aa bb bb aa aa bb aa aa 输出:aa:5 bb:3
8.7 重载函数调用运算符 x(arg1, arg2,arg3) x.operator( ) (arg1,arg2,arg3) 举例:assoc类的print_all( )成员函数用于输出数组,现在希望外部函数来实现。 class assoc { friend class assoc_iterator; //…… }; class assoc_iterator { const assoc* cs; int i; public: assoc_iterator(const assoc& s) { cs=&s; i=0; } pair * operator( ) ( ) { return (i<cs->free? &cs->vec[i++]:0; } }; void main( ) { const MAX=256; char buf[MAX]; assoc vec(512); while(cin>>buf) vec[buf]++; assoc_iterator next(vec); pir *p; while(p=next( )) cout<<p->name<<“:”<<p->val<<endl; } 指向要访问的数组, 下标从0开始
8.8 重载递引用运算符 ->运算符函数返回是中间结果,在此结果上施加内定义的->运算。 class B; class A { public: B* operator->( ); //…… }; class B { //…… }; void main( ) { A a; …a->b… } 举例: class A { private: char *cp; public: void a( ); void b( ); void c( ); A(char *r) { cp=new char[strlen(r)+1]; strcpy(cp,r); } }; 1、在对象a上执行A::operator->( ) 2、返回值放入类型为B*的临时对象x中 3、求x->b得结果 A的运算符函数返回B的指针,再通过内定义函数访问B的成员(a.operator->( ))->b
仅为了重用A中的方法,B要重新定义函数 class B { private: A *delegate; public: void a( ) { delegate->a( ); } void b( ) { delegate->b( ); } void c( ) { delegate->c( ); } void d( ); B(char *r=0) { delegate=new A(r); } }; 解决方法(适用非运算符重载函数)——B中重载->运算符: class B { private: A *delegate; public: void d( ); A* operator->( ) { return delegate; } B(char *r=0) { delegate=new A(r); } }; B b; b.d( ); b->a( ); b->b( ); b->c( ); 注意:b并不是指针
习题: 1、写出程序执行结果: #include<iostream.h> class myclass { int i; float j; public: myclass(int x=0, float y=0) { i=x; j=y; } myclass operator( ) (int k, float m); void display( ) { cout<<i<<“ “<<j<<endl; } }; myclass myclass::operator( ) (int k, float m) { i=k+10; j=m+10.5; return *this; } void main( ) { myclass obj1(10, 11.5); obj1.display( ); obj1(100, 6.9); obj1.display( ); } 10 11.5 110 17.4
2、填空: #include<iostream.h> #include<string.h> class Name { public: Name( ) { pName=0; } Name(char *pn) { copyName(pn); } Name(Name &s) { copyName(s.pName); } ~Name( ) { deleteName( ); } Name=( Name &s ) { deleteName( ); copyName(s.pName); return ; } void display( ) { cout<<pName<<endl; } protected: void copyName(char *pN); void ; char *pName; }; void copyName(char * pN) { pName=new ; ; } void deleteName( ) { delete ; } & operator *this deleteName( ) Name:: char [strlen(pN)+1] strcpy(pName, pN) Name:: pNmae
double & operator( ) (int x, int y); 3、下面是一个用一维数组表示的矩阵类: class Matrix { private: double * elem; int row, col; public: Matrix( int row1, int col1 ); ~Matrix( ); }; (1) 完成构造和析构函数的定义。 (2) 要实现用m(i,j)存取矩阵的元素,需增加什么运算符重载,写出此运算符重载 函数的定义。 Matrix:: Matrix(int row1, int col1) { row=row1; col=col1; elem=new double[row*col]; } Matix::~Matrix( ) { delete [ ] elem; } double& Matrix:: operator( ) (int x, int y) { return elem[col*(x-1)+y-1]; }