C++运算符重载

1. 一般运算符的重载

复数类

   1 class complex {
   2         double re, im;
   3 public:
   4         complex(double r, double i);
   5         complex add(complex b);
   6         complex multiply(complex b);
   7 };
   8 void f() {
   9     complex a(1.0, 1.0), b(-1.0, -2.0), c(0, 0);
  10     a = b.add(c); 
  11     b = b.add(c.multiply(a)); 
  12     c = a.multiply(b).add(complex(1,2)); 
  13     // a = b+c; 
  14     // b = b + c * a;
  15     // c = a * b + complex(1, 2);
  16 }

运算符重载:为类型添加运算符

   1 class complex {
   2     double re, im;
   3 public:
   4     complex(double r, double i);
   5     complex  operator+ (complex  b);
   6     complex  operator* (complex  b);
   7 };
   8 int main() {
   9     complex a(2, 3), b(-1, 2), c(3, 4);
  10     a = b + c;   // b.operator+(c)
  11     b = b + c * a; // b.operator+(c.operator*(a))
  12     c = a * b + complex(1, 2); //a.operator*(b).operator+(complex(1,2)); 
  13 }
  14 complex complex::operator+(complex b) {
  15     return complex(re + b.re, im + b.im);
  16 }

能够重载的运算符

+     -    *    /    %    ^    &    |    ~    !    =    <    >
+=    -=    *=    /=    %=    ^=    &=    |=    <<    >>
>>=    <<=   ==    !=    <=    >=    &&    ||   ++    
--    ,    ->    [ ]     ()    new    new[ ]     delete    delete[ ]

不能重载的运算符

::   .    .*  ?:    sizeof    typeid

重载的运算符是一个名字和调用方法特殊的函数。可以用成员函数的方式重载,也可以用普通函数的方式重载。

complex operator+( complex c, complex d);

重载的运算符的参数至少有一个是类

int operator+(int a, int b); //error
bool operator==(char *, char *); // error

[ ], (), =, ->运算符必须以成员函数方式重载。运算符重载不会改变运算符原有的优先级、操作数数目、结合性。

complex a, b, c;  
a+b*c;

不能够自己创造运算符,比如**。尽量不要改变运算符原来的语义。

二元运算符可以用带一个参数的成员函数的形式,也可以用带两个参数的普通函数的形式重载。区别:成员函数重载,第一个参数只能是类的对象。

   1 class X {
   2 public:
   3     void operator+( int i);
   4     X( int a );
   5 };
   6 void operator+( X a, X b);
   7 void operator+( X a, double b);
   8 void f( X a) {
   9     a+1;  // 相当于a.operator+(1);
  10     1+a;  //相当于 operator+(1, a);
  11     a+1.0;  //相当于 operator+(a, 1.0);
  12 }

单目运算符可以用不带参数的成员函数的形式,也可以用带一个参数的普通函数的形式重载

   1 class X {
   2         X* operator&(); // &a
   3         X* operator&(X b);  // 双目 a & b
   4         X operator++(); // ++a
   5 };
   6 X operator-(X); // -a
   7 X operator--(X); //--a
   8 void f( X a) {
   9     &a;  // 相当于a.operator&();
  10     -a;  //相当于 operator-(a);
  11     --a;  //相当于 operator--(a);
  12     ++a; //相当于 a.operator++();
  13 }

完整的complex运算符

   1 class complex {
   2     double re, im;
   3 public:
   4     complex( double r = 0, double i = 0): re(r), im (i) { }
   5     double& real() { return re; }
   6     double& imag() { return im; }
   7     complex operator+() { return *this; }
   8     complex operator-() { return complex(-re, -im); }
   9     complex operator+=( complex c) { re+= c.re; im+= c.im; return *this; }
  10     complex operator-=( complex c);
  11     complex operator*=( complex c);
  12     complex operator/=( complex c);
  13 };
  14 
  15 complex operator+( complex a, complex b) {
  16     a+=b; return a;
  17 }
  18 complex operator-( complex a, complex b);
  19 complex operator*( complex a, complex b);
  20 complex operator/( complex a, complex b);

练习:创建分数类,定义尽可能多的运算符

2. operator<<, operator>> 输入输出

移位运算符,经常重载作输入输出用

   1 void f( complex c) {
   2     cout << “ hello world” << 100;
   3     cout << c ;  // operator<<(cout, c)
   4 }
   5 ostream &operator<<(ostream&os, complex c) {
   6     return os << “(” << c.real() << “+” << c.imag() << “i)”;
   7 }
   8 istream &operator>>(istream&is, complex &c) {
   9     return is >> c.real() >> c.imag();
  10 }

练习:输出输出Date类型的值

3. operator= 赋值

赋值运算符,自定义对象赋值行为

Class complex;
complex c1;
complex c2(c1); //拷贝构造
c2 = c1;
void f( complex c);
f( c1 ); //拷贝构造

如果没有自定义赋值运算符,默认的赋值行为:类中逐个成员赋值。

   1 class string {
   2     char *str; 
   3     int size;
   4 public:
   5     string( char *s ) {
   6         size = strlen(s) +1;
   7         str = new char[size];
   8         strcpy(str, s);
   9     }
  10     ~string( ) { 
  11         delete [ ] str; 
  12     }
  13     string( const string& c){
  14         size = c.size;
  15         str = new char [size]; 
  16         strcpy(str, c.str); 
  17     } 
  18     string& operator=(const string&c){
  19         if(this != &c) {
  20             delete [ ] str; 
  21             size = c.size;
  22             str = new char[size]; 
  23             strcpy(str, c.str);
  24         } 
  25         return *this;
  26     }
  27 };
  28 
  29 int main() {
  30     string c ( “123” );
  31     string d ( c );
  32     c = d; // c.operator=(d)
  33 }

4. operator type 类型转换

可以将自定义类型转换为其他类型

   1 class string {
   2     char * str;   int size;
   3 public:
   4     operator char *() {
   5         return str;
   6     }
   7 };

   1 class istream {
   2     bool flag;
   3 public:
   4     operator bool( ) {
   5         return flag;
   6     } 
   7     istream& operator>>(double);
   8 };
   9 extern istream cin;
  10 int main( ) {
  11     int i;
  12     while( cin >> i ) { /*...*/  }
  13 }

5. operator[ ] 数组取成员

让对象像数组一样使用

   1 class string {
   2     char *str;
   3     int size;
   4 public:
   5     char &operator[](int i) {
   6         return str[i];
   7     }
   8     char operator[](int i) const {
   9         return str[i];
  10     }
  11 };
  12 void f( string s) {
  13     cout << s[10]; //相当于s.operator[](10)
  14 }

operator[]运算符的参数可以是任何类型,但是只能是二元的

   1 class Dictionary {
   2 public:
   3     string &operator[ ](string word) {
   4         //...
   5     }
   6 };
   7 void f( Dictionary s) {
   8     cout << s[ “hello” ]; 
   9 }

练习:写一个intArray类

6. operator() 函数调用

重载(),让对象可以像函数一样使用

   1 class Add {
   2     int base;
   3 public:
   4     Add(int b) : base(b) { }
   5         int operator()(int a) { return b + a; }
   6 };
   7 void f( Add add) {
   8     Add add2( 2 );
   9     int c = add2( 8 );  // 相当于 add2.operator()(8);
  10     c = add(5);
  11 }

operator()的参数个数可以任意。重载()的类又叫做仿函数——一种带状态的函数

7. operator++, operator-- 自增自减

++和--运算符分为前置和后置两种。

   1 class Integer {
   2     int i;
   3 public:
   4     Integer& operator++() {  //前置
   5         ++i;   return *this;
   6     }
   7     Integer operator++(int) { //后置
   8         Integer temp(*this);
   9         i++;   return temp;             
  10     }
  11 };
  12 void  f( Integer i ) {
  13     i++; // i.operator++(0);
  14     ++i; // i.operator++();
  15 }

练习: 写一个clock类

8. operator-> 指针取成员

重载->让一个对象可以像指针一样使用

   1 class autoptr{
   2     Person *person;
   3 public:
   4     autoptr( Person *p) : person(p) { }
   5     ~autoptr() { delete person; } 
   6     Person *operator->( ) { return person; }
   7     Person &operator*( ) { return *person; }
   8 };
   9 int main() {
  10     autoptr p( new Teacher);
  11     p->print( );
  12 }

9. new, delete, new[ ], delete[ ] 内存分配

自定义对象new和delete的行为

   1 class memory{
   2 public:
   3     void *operator new(size_t  s) {
   4         return  malloc( s );
   5     }
   6     void operator delete(void *p) {
   7         free(p);
   8     }
   9 };
  10 int main() {
  11     memory *p = new memory; 
  12     // p = memory::new (sizeof(memory)); call constructor on p;
  13     delete p; 
  14     // p->~memory(); memory::operator delete(p);
  15 }

10. string例子

   1 class String{
   2     char *str; 
   3     int size;
   4 public:
   5     String(const char *s="");
   6     String(const String&s);
   7     String& operator=(const String&);
   8     virtual ~String();
   9     char &operator[ ](int i);
  10     char operator[ ](int i) const;
  11     bool operator==(const String &) const;
  12     int length() const;
  13     operator char*();
  14     friend ostream& operator<<(ostream&os, const String &s);
  15     friend istream& operator>>(istream&is, String &s);
  16 };

The End

ch3n2k.com | Copyright (c) 2004-2020 czk.