构造
#include<iostream> using namespace std; class Vector { int x,y; public: Vector(){};//默认构造函数 Vector(int x1,int y1)//重载构造函数 { x=x1;y=y1; } Vector operator+(Vector v)//成员函数方式重载运算符"+" { Vector tmp;//定义一个tmp对象 tmp.x=x+v.x; tmp.y=y+v.y; return tmp;//返回tmp对象 } Vector operator-(Vector v)//成员函数方式重载运算符"-" { Vector tmp;//定义一个tmp对象 tmp.x=x-v.x; tmp.y=y-v.y; return tmp;//返回tmp对象 } void display() { cout<<"("<<x<<","<<y<<")"<<endl; } }; void main() { Vector v1(6,8),v2(3,6),v3,v4; cout<<"v1="; v1.display(); cout<<"v2="; v2.display(); v3=v1+v2; cout<<"v1+v2="; v3.display(); v4=v1-v2; cout<<"v1-v2="; v4.display(); system("pause"); } //------------- #include<iostream> using namespace std; class Vector1 { int x,y; public: Vector1(){}; Vector1(int x1,int y1){x=x1;y=y1;} friend Vector1 operator+(Vector1 v1,Vector1 v2)//友元函数方式 { Vector1 tmp; tmp.x=v1.x+v2.x; tmp.y=v1.y+v2.y; return tmp; } friend Vector1 operator-(Vector1 v1,Vector1 v2)//友元函数方式 { Vector1 tmp; tmp.x=v1.x-v2.x; tmp.y=v1.y-v2.y; return tmp; } void display() { cout<<"("<<x<<","<<y<<")"<<endl; } }; void main() { Vector1 v1(6,8),v2(3,6),v3,v4; cout<<"v1="; v1.display(); cout<<"v2="; v2.display(); v3=v1+v2; cout<<"v1+v2="; v3.display(); v4=v1-v2; cout<<"v1-v2="; v4.display(); system("pause"); } //------------------ /*bool operator<(const Date1 d1) bool operator>(const Date1 d1) bool operator==(const Date1 d1)*/ #include<iostream> using namespace std; class Date1 { int year;int month;int day; public: Date1(){};//默认构造函数,第一个没用,系统预留 Date1(int y,int m,int d)//重载构造函数 { year=y;month=m;day=d; } Date1(const Date1 &d1)//复制构造函数,第三个函数好像是复制第二个函数里面的 { year=d1.year; month=d1.month; day=d1.day; } bool operator<(const Date1 d1) { if((year<d1.year)||(year=d1.year&&month<d1.month)||(year==d1.year&&month==d1.month&&day<d1.day)) return true; else return false; } bool operator==(const Date1 d1) { if(year==d1.year&&month==d1.month&&day&&d1.day) return true; else return false; } bool operator>(const Date1 d1) { if((year>d1.year)||(year=d1.year&&month>d1.month)||(year==d1.year&&month==d1.month&&day>d1.day)) return true; else return false; } void disp() { cout<<year<<"."<<month<<"."<<day<<endl; } }; void main() { Date1 d1(2008,10,1),d2(2010,10,1),d3(d1); cout<<"d1:"; d1.disp(); cout<<"d2:"; d2.disp(); cout<<"d3:"; d3.disp(); cout<<"d1<d2:"<<(d1<d2)<<endl; cout<<"d1>d2:"<<(d1>d2)<<endl; cout<<"d1==d2:"<<(d1==d2)<<endl; cout<<"d1==d3:"<<(d1==d3)<<endl; system("pause"); } //-----------------
1 :operator+ 一般可以间接的通过operator+=来实现 2008-05-05 17:51:43 2 分类: C/C++ 3 小技巧:operator+ 一般可以间接的通过operator+=来实现 4 5 class Matrix { 6 public: 7 Matrix& operator+=(const Matrix& rhs) { 8 // ... 9 return *this; 10 } 11 12 const Matrix operator+ (const Matrix& rhs) const { 13 Matrix tmp(*this); // 调用拷贝构造函数,通过复制产生一个新的object 14 tmp += rhs; // 利用operator += 实现operator + 15 return tmp; // 返回计算结果 16 }; 17 }; 18 19 20 21 22 看下面的代码: 23 int func(int j) { 24 int i = 30; 25 i += j; 26 return i; 27 } 28 这个函数很简单,大家也都认为它没有语法错误。函数返回时,变量i会被销毁,但是函数仍然成功的将i的值返回出来了。呵呵,有点神奇。类比一下: 29 const Matrix operator+ (const Matrix& rhs) const { 30 Matrix tmp(*this); // 调用拷贝构造函数,通过复制产生一个新的object 31 tmp += rhs; // 利用operator += 实现operator + 32 return tmp; // 返回计算结果 33 }; 34 函数返回时,变量tmp会被销毁,但是函数仍然可以成功的将tmp的值返回出来。 35 36 注意这句return tmp;其中所隐藏的程序行为。函数返回一个值时,先把要返回的值复制一份(调用copy constructor,拷贝构造函数),放到别处,然后再销毁函数中各种需要销毁的变量,再将控制权交还给函数的调用者,调用者看到的返回值实际上是复制的值。 37 38 举例来说。比如我写 39 Matrix m = m1 + m2; 40 则m1+m2会调用Matrix::operator +(函数),函数返回时,先将返回值复制一份(调用copy constructor,拷贝构造函数),然后销毁函数中的变量tmp。函数返回后,利用复制好的值对变量m进行构造。当Matrix m = m1 + m2;这一整条语句都执行完毕后,m1+m2得到的值因为是临时值,不再使用,所以进行销毁,也就是说在这个时候把复制的值销毁。 41 这样看来,短短的一句Matrix m = m1 + m2;就要产生多个对象并进行销毁。(第一个:operator +中的tmp对象,第二个:返回时需要复制产生一个临时对象,第三个:正式需要的对象m)构造函数和析构函数被大量的调用,效率较低。这种情况下,编译器一般会对其进行优化,尽可能产生较少的对象,减少构造函数和析构函数的调用。但是最终要产生多少对象,这完全取决于编译器的优化能力:有的编译器可能完全不优化,产生三个对象;有的编译器则只产生两个对象(返回时复制一份的对象本身就是上一层函数的变量m);最理想的情况就是只产生一个对象(变量tmp,返回时复制一份的对象,上一层函数的变量m三者合一)。 42 可以做这样一个实验,定义一个类,在构造函数、拷贝构造函数、析构函数中分别输出不同的信息(例如cout << "construct" << endl;),然后定义一个函数来返回这个类的对象。可以看到不同的编译器可能输出不同的结果。 43 #include <iostream> 44 using namespace std; 45 class Test { 46 public: 47 Test() { cout << "construct" << endl; } 48 Test(const Test&) { cout << "copy construct" << endl; } 49 ~Test() { cout << "descruct" << endl; } 50 }; 51 Test func() { 52 Test t; 53 return t; 54 } 55 int main() { 56 Test t = func(); 57 return 0; 58 } 59 60 我用vc2005测试,debug模式构造了两个对象(输出四行),release模式则只构造了一个对象(输出两行)。 61 62 注意以下几种用法是错误或者不推荐的。 63 1. 返回即将被销毁的变量的引用。错误的做法。因为变量被销毁,引用它也就没有意义。 64 2. 返回指向即将被销毁的变量的指针。错误的做法。理由同上。 65 3. 通过new分配内存并创建对象,返回它的引用或返回指向它的指针。不推荐。例如: 66 Matrix m = (m1 + m2) + m3; 67 则m1+m2的结果一直保存着,无法进行释放。 68 必须写: 69 Matrix* pTemp1 = &(m1 + m2); 70 Matrix* pTemp2 = &(*pTemp1 + m3); 71 m = *pTemp2; 72 delete pTemp1; 73 delete pTemp2; 74 这种烦琐的方式显然不是我们想要的。 75 4. 定义一个static变量,返回它的引用或返回指向它的指针。不推荐。 76 Matrix m = m1 + m2; // 没问题 77 Matrix m = (m1+m2) + (m3+m4); // 错误 78 因为用了static,每次相加的结果都是放到同一个变量中进行保存的。C++没有规定到底先计算m1+m2还是先计算m3+m4。如果先计算m1+m2,则后来计算m3+m4时就会把m1+m2的结果覆盖;如果先计算m3+m4,则后来计算m1+m2时就会把m3+m3的结果覆盖,无论怎么计算,最后都无法得到正确的结果。 79 80 引用: 81 不过,拷贝构造函数,operator =操作符,还有析构函数一般都要一起出现。 82 假如其中一个可以不要,那么一般三个都可以不要。 83 84 如果不定义自己的拷贝构造函数、operator =、析构函数,则C++编译器会自动产生一个默认的。实际使用时,先考虑使用默认的拷贝构造函数、operator=、析构函数是否满足需要,如果不满足,就自己定义之。通常,如果成员中使用了指针,就需要自己定义。 85 86 最后,operator +返回的类型要加上const。这是为了避免出现下面的情况: 87 (m1 + m2) = m3; 88 如果m1+m2是一个Matrix类型,则它可以被赋值(调用operator=),但是上面的语句是不合逻辑的,不应该被允许。只要让m1+m2是一个const Matrix类型,就可以让上面的语句编译出错。从而避免这种不合逻辑的写法。 89 90 91 92 小结: 93 编写加法运算符,最合理的实现可能就是这个了: 94 const Matrix operator+ (const Matrix& rhs) const { 95 Matrix tmp(*this); // 调用拷贝构造函数,通过复制产生一个新的object 96 tmp += rhs; // 利用operator += 实现operator + 97 return tmp; // 返回计算结果 98 }; 99 程序必须先追求正确,然后才能追求高效。从上面四种不推荐的情况来看,返回引用或者指针都不是好的做法(有些做法是错误的,有些做法隐含了潜在错误),因此只好返回实际的对象了。 100 通过编译器的优化,返回一个对象的效率并没有大家想象的那么不堪,实际构造对象的个数往往并不多。没有必要为了这点性能去担忧。 101 102 103 104 105 #include<iostream> 106 using namespace std; 107 class MyClass2 108 { 109 int n; 110 public: 111 MyClass2(int i){n=i;} 112 operator ++(){n++;}//vc6.0支持,vs2012不支持 113 operator++(int){n+=2;} 114 void display() 115 { 116 cout<<"n="<<n<<endl; 117 } 118 }; 119 void main() 120 { 121 MyClass2 A(5),B(5); 122 A++; 123 ++B; 124 A.display(); 125 B.display(); 126 system("pause"); 127 } 128 #include<iostream> 129 using namespace std; 130 class MyClass2 131 { 132 int n; 133 public: 134 MyClass2(int i){n=i;} 135 const int operator ++(){n++;return n;} 136 const int operator++(int){n+=2;return n;} 137 void display() 138 { 139 cout<<"n="<<n<<endl; 140 } 141 }; 142 void main() 143 { 144 MyClass2 A(5),B(5); 145 A++; 146 ++B; 147 A.display(); 148 B.display(); 149 system("pause"); 150 }