标签:
操作符重载
复数:3+4i
Complex
c1 - (c2 + c3)
c1.sub (c2.add (c3))
一、操作符标记和操作符函数的对应关系
1.双目操作符:L#R
成员函数形式:L.operator# (R) //(p.s. 会被进一步编译为operator#(&L, R);) (p.s. 表达式 L
# R 中, 左操作数 作为了成员函数调用者,右操作数作为了成员函数的调用实际参数,我们把这种通俗地称为"左调右参")
全局函数形式:::operator# (L, R) //(p.s.表达式 L # R中, 左操作数作为了全局函数的第一实际参数,右操作数作为了全局函数的第二实际参数, 俗称"左一右二")
2.单目操作符:#O或O#
成员函数形式:O.operator# () //(p.s. 会被进一步编译为operator#(&O))
全局函数形式:::operator# (O)
3.三目操作符:不考虑//三目操作符号不能重载。
二、双目操作符
1.+/-/*//
操作数在计算前后不变。
表达式的值是右值。
1 /* 2 * 双目操作符+/-的实现举例 3 * */ 4 #include <iostream> 5 using namespace std; 6 class Complex { 7 public: 8 Complex (int r = 0, int i = 0) : 9 m_r (r), m_i (i) {} 10 void print (void) const { 11 cout << m_r << ‘+‘ << m_i << ‘i‘ << endl; 12 } 13 // 第一个const:返回右值 14 // 第二个const:支持常量型右操作数 15 // 第三个const:支持常量型左操作数 16 const Complex operator+ ( 17 const Complex& r) const { 18 return Complex (m_r + r.m_r, m_i + r.m_i); 19 } 20 private: 21 int m_r; 22 int m_i; 23 friend const Complex operator- (const Complex&, 24 const Complex&);//友元不受访控属性控制,可以放在该类的任何部分。 25 }; 26 const Complex operator- (const Complex& l, 27 const Complex& r) { 28 return Complex (l.m_r - r.m_r, l.m_i - r.m_i); 29 } 30 int main (void) { 31 const Complex c1 (1, 2); 32 c1.print (); 33 const Complex c2 (3, 4); 34 Complex c3 = c1 + c2; //编译器将处理为 c3 = c1.operator+ (c2) 35 c3.print (); // 4+6i 36 // (c1 + c2) = c3; 37 c3 = c2 - c1; // c3 = ::operator- (c2, c1) 38 c3.print (); // 2+2i 39 return 0; 40 }
2.+=/-=/*=...
(p.s.这几个操作符会导致左操作数变化,右操作数不变,操作结果是左操作数的引用(匿名指针常量*p_b)。)
表达式的值是左值,是左操作数的引用。
(a += b) = c;
1 /* 2 *操作符重载练习 3 */ 4 #include <iostream> 5 using namespace std; 6 class Complex { 7 public: 8 Complex (int r = 0, int i = 0) : 9 m_r (r), m_i (i) {} 10 void print (void) const { 11 cout << m_r << ‘+‘ << m_i << ‘i‘ << endl; 12 } 13 Complex& operator+= (const Complex& r) { 14 m_r += r.m_r; 15 m_i += r.m_i; 16 return *this; 17 } 18 friend Complex& operator-= (Complex& l, 19 const Complex& r) { 20 l.m_r -= r.m_r; 21 l.m_i -= r.m_i; 22 return l; 23 } 24 private: 25 int m_r; 26 int m_i; 27 }; 28 int main (void) { 29 Complex c1 (1, 2), c2 (3, 4); 30 c1 += c2; // c1.operator+= (c2) 31 c1.print (); // 4+6i 32 Complex c3 (5, 6); 33 (c1 += c2) = c3; 34 c1.print (); // 5+6i 35 c1 -= c2; // ::operator-= (c1, c2) 36 c1.print (); // 2+2i 37 (c1 -= c2) = c3; 38 c1.print (); // 5+6i; 39 return 0; 40 }
3.<</>>
int i = 10;
float f = 1.23;
Complex c (...);
cout << c << i << f << endl;
cin >> c;
左操作数ostream/istream类型,不能是常量,不能拷贝(拷贝构造函数被处理成私有成员了)。
右操作数自定义类型,对于<<可以是常量,对于>>不能是常量。
表达式的值是左操作数的引用。
::operator<< (cout, c).operator<< (i).operator<< (f).operator<< (endl);
1 /* 2 * 操作符<< 和 >>重载练习 3 * 4 */ 5 #include <iostream> 6 using namespace std; 7 class Complex { 8 public: 9 Complex (int r = 0, int i = 0) : 10 m_r (r), m_i (i) {} 11 void print (void) const { 12 cout << m_r << ‘+‘ << m_i << ‘i‘ << endl; 13 } 14 friend ostream& operator<< (ostream& os, 15 const Complex& r) { 16 return os << r.m_r << ‘+‘ << r.m_i << ‘i‘; 17 } 18 friend istream& operator>> (istream& is, 19 Complex& r) { 20 return is >> r.m_r >> r.m_i; 21 } 22 private: 23 int m_r; 24 int m_i; 25 }; 26 int main (void) { 27 Complex c1 (1, 2), c2 (3, 4); 28 cout << c1 << endl << c2 << endl; 29 // ::operator<<(::operator<<(cout,c1).operator<<( 30 // endl),c2).operator<<(endl); 31 cin >> c1 >> c2; 32 cout << c1 << endl << c2 << endl; 33 return 0; 34 }
三、单目操作符
1.-(取负)/!/~
操作数不变。
表达式的值是右值。
1 /* 2 * 单目操作符重载练习 3 * */ 4 #include <iostream> 5 using namespace std; 6 class Complex { 7 public: 8 Complex (int r = 0, int i = 0) : 9 m_r (r), m_i (i) {} 10 void print (void) const { 11 cout << m_r << ‘+‘ << m_i << ‘i‘ << endl; 12 } 13 const Complex operator- (void) const { 14 return Complex (-m_r, -m_i); 15 } 16 friend const Complex operator~ ( 17 const Complex& o) { 18 return Complex (o.m_i, o.m_r); 19 } 20 private: 21 int m_r; 22 int m_i; 23 }; 24 int main (void) { 25 const Complex c1 (1, 2); 26 Complex c2 = -c1; // c2=c1.operator-() 27 c2.print (); // -1+-2i 28 Complex c3 = ~c1; // c3=::operator~(c1) 29 c3.print (); // 2+1i; 30 return 0; 31 }
2.前++/前--
操作数变。
表达式的值是运算以后的值。
表达式的值是左值,操作数的引用。
(++i) = 100;
++++++i;
1 /* 2 * 前缀自增自减操作符重载练习 3 */ 4 #include <iostream> 5 using namespace std; 6 class Complex { 7 public: 8 Complex (int r = 0, int i = 0) : 9 m_r (r), m_i (i) {} 10 void print (void) const { 11 cout << m_r << ‘+‘ << m_i << ‘i‘ << endl; 12 } 13 Complex& operator++ (void) { 14 ++m_r; 15 ++m_i; 16 return *this; 17 } 18 friend Complex& operator-- (Complex& o) { 19 --o.m_r; 20 --o.m_i; 21 return o; 22 } 23 private: 24 int m_r; 25 int m_i; 26 }; 27 int main (void) { 28 Complex c1 (1, 2); 29 Complex c2 = ++c1; // c2=c1.operator++() 30 c1.print (); // 2+3i 31 c2.print (); // 2+3i 32 (++c1) = Complex (10, 20); 33 c1.print (); // 10+20i; 34 (++++++c1).print (); // 13+23i 35 c2 = --c1; // c2=::operator--(c1) 36 c1.print (); // 12+22i 37 c2.print (); // 12+22i 38 return 0; 39 }
3.后++/后--
自增自减操作符
++是自增操作符,--是自减操作符。他们可以对变量进行操作,可以实现把变量内部的数字加一或者减一。这两个操作符写在变量前面的时候被称为"前缀操作
符",写在后面是被称为"后缀操作符"。这两种情况下,其效果都是将变量的值加一或者减一。但是,它们之间有一点不同。作为前缀操作符,会先完成自增或者
自减,然后再供其他操作使用,作为后缀操作符,会在完成自增或者自减的同时,提供一个自增自减前的值给其他操作使用。
1 /* 2 *以下实现了复数类Complex的后++、--操作符运算 3 */ 4 #include <iostream> 5 using namespace std; 6 7 class Complex { 8 public: 9 Complex (int r = 0, int i = 0) : 10 m_r (r), m_i (i) {} 11 12 void print (void) const 13 { 14 cout << m_r << ‘+‘ << m_i << ‘i‘ << endl; 15 } 16 17 Complex& operator++(void) 18 { 19 ++m_r; 20 ++m_i; 21 return *this; 22 } 23 24 const Complex operator++ (int/*制作了一个哑元,用意在于和前置操作符++的实现Complex& operator++(void)形成重载*/) 25 { 26 Complex old (*this); 27 ++m_r; 28 ++m_i; 29 return old; 30 } 31 32 // 用全局函数的方式来实现后-- 33 friend const Complex operator-- (Complex& o, int/*制作哑元,用意在于和前置操作符--的实现Complex& operator-- (Complex& o)形成重载*/) 34 { 35 Complex old (o); 36 --o.m_r; 37 --o.m_i; 38 return old; 39 } 40 41 private: 42 int m_r; 43 int m_i; 44 }; 45 46 47 int main (void) 48 { 49 Complex c1 (1, 2); 50 Complex c2 (0, 0); 51 c2 = c1++; // step1:制作一个临时的匿名的c1(这里称为c1_bak); 52 // step2:给c1加1; 53 // step3:将临时的匿名的c1_bak赋值给c2; 54 // 以上三步是后缀自增自减操作符运算的基本的永恒的步骤。切勿以为++的优先级低于赋值操作符号,要知道赋值操作符号优先级是很底的。 55 // 编译器编译表达式c1++时将试图按照c1.operator++(0)调用Complex的成员函数const Complex Complex::operator++(int); 56 57 c1.print (); // 2+3i; 58 c2.print (); // 1+2i; 59 //(c1++) = c2;//ERROR。 表达式:c1++的计算结果是常量 60 //c1++++++;//ERROR。 表达式c1++的计算结果是常量 61 62 c2 = c1--;// 编译器编译表达式c1--时将试图按照::operator--(c1,0)调用匿名命名空间的const Complex operator--(Complex, int); 63 c1.print (); // 1+2i 64 c2.print (); // 2+3i 65 return 0; 66 }
实际上可以进一步理解后++/后--
int i = 1;
int j = 0;
j = i++;//OK.
i++ = 100;//ERROR.错误:赋值运算的左操作数必须是左值,而表达式i++的计算结果是个右值. (p.s. ++i的计算结果是个左值。)
/*
* 对于表达式i++;编译器将按照如下步骤处理:
* step1:制作一个i的副本(临时的匿名的变量,这里临时记作i_bak.)
* step2:给i增加1
* step3:将i的副本i_bak返回作为表达式i++的计算结果
*
* 结论:(1)C/C++中,基本类型的临时匿名变量是不可更改的。表达式的计算结果是个右值。
* (2)C/C++中,后置++/后置--计算结果导致操作数增加或者减少1。
*/
四、其它操作符
1.下标操作符:[]
int arr[10] = { ... };
arr[1] = 10;
cout << arr[1] << endl;
-----------------------
class Array { ... };
Array arr (...);
arr[1] = 10;
cout << arr[1] << endl;
双目操作符[],左操作数是一个具有容器特性的对象,右操作数是容器中特定数据元素的索引(基零的下标)。
下标表达式的值可以是左值,也可以是右值,由容器对象的常属性决定。常容器下标表达式的值是右值,非常容器下标表达式的值是左值。
1 /* 2 *下标操作符重载练习 3 * */ 4 #include <iostream> 5 using namespace std; 6 class Array { 7 public: 8 Array (size_t size = 1) : 9 m_data (new int[size]) {} 10 ~Array (void) { 11 if (m_data) { 12 delete m_data; 13 m_data = NULL; 14 } 15 } 16 int& operator[] (size_t i) { 17 return m_data[i]; 18 } 19 const int& operator[] (size_t i) const { 20 return const_cast<Array&> (*this)[i]; 21 //return (*(const_cast<Array*> this))[i];//ERROR 22 } 23 private: 24 int* m_data; 25 }; 26 int main (void) { 27 Array arr (10); 28 for (size_t i = 0; i < 10; ++i) 29 arr[i] = i; // arr.operator[](i) = i; 30 arr[0]++; 31 const Array& cr = arr; 32 for (size_t i = 0; i < 10; ++i) 33 cout << cr[i] << ‘ ‘; 34 cout << endl; 35 // cr[0]++; 36 return 0; 37 }
2.函数操作符:()
如果为一个类定义了形如:
返回类型 operator() (形参表) {...}
的操作符函数,那么这个类所实例化的对象就可以被当做函数使用。
1 /* 2 * 小括号操作符重载练习 3 */ 4 #include <iostream> 5 using namespace std; 6 class Square { 7 public: 8 double operator() (double x) { 9 return x * x; 10 } 11 }; 12 class Integer { 13 public: 14 explicit Integer (int i = 0) : m_i (i) {} 15 void print (void) const { 16 cout << m_i << endl; 17 } 18 Integer& operator() (int i) {//重载小括号操作符 19 m_i += i; 20 return *this; 21 } 22 Integer& operator, (int i) {//重载逗号操作符 23 m_i += i; 24 return *this; 25 } 26 operator int (void) const { 27 return m_i; 28 } 29 private: 30 int m_i; 31 }; 32 void foo (const Integer& i) { 33 i.print (); 34 } 35 Integer bar (void) { 36 return Integer (300); 37 } 38 int main (void) { 39 Square square; 40 cout << square (3) << endl; 41 //square(3)编译时处理成成员函数调用square.operator() (3); 42 Integer i (10); 43 i (1) (2) (3) (17); 44 i.print (); // 33 45 //i.operator()(1).operator()(2).operator()(3).operator()(17); 46 i, 1, 2, 3, 17; 47 //i.operator,(1).operator,(2).operator,(3).operator,(17); 48 i.print (); // 56 49 i = (Integer)100; 50 i.print (); 51 foo (static_cast<Integer> (200)); 52 bar ().print (); 53 int n = i; 54 cout << n << endl; 55 return 0; 56 }
3.解引用(*)和间接访问(->)操作符
通过对这两个操作符的重载,可以实现以指针的方式使用类类型的对象。
特别注意:解引用操作符和间接访问操作符是完全不同的:
1) 解引用操作符是(*),解引用(*)操作符运算结果是目标对象本身。
2) 间接访问操作符(也称为成员访问操作符)是用来访问结构体(类)、联合体等复杂数据类型成员的操作符,包括(.)和(->)两个。 其中:
间接访问操作符(.)是根据目标对象来访问其成员的,是不能被重载的;
间接访问操作符(->)是根据目标对象的地址来访问其成员的,是可以重载的!重载间接访问操作符(->)时应返回目标对象的地址以图完成根据目标对象的地址来访问其成员。
1 /* 2 * 操作符 * 和 -> 重载练习 3 * (p.s. C++库中提供的auto_ptr和smart_ptr就是通过重载解引用操作符,间接访问操作符来模拟指针实现了自动垃圾回收。
我们可以使用auto_ptr或smart_ptr来创建类的堆对象,而不再时刻揪心内存泄露。) 4 * */ 5 #include <iostream> 6 #include <memory> 7 using namespace std; 8 class A { 9 public: 10 A (void) { 11 cout << "构造" << endl; 12 } 13 ~A (void) { 14 cout << "析构" << endl; 15 } 16 void hello (void) { 17 cout << "Hello, World !" << endl; 18 } 19 }; 20 class PA { 21 public: 22 PA (A* p = NULL) : m_p (p) {} 23 ~PA (void) { 24 if (m_p) { 25 delete m_p; 26 m_p = NULL; 27 } 28 } 29 A& operator* (void) const { 30 return *m_p; 31 } 32 A* operator-> (void) const { 33 // return &**this; 34 return m_p; 35 } 36 PA (PA& that) : m_p (that.release ()) {} 37 PA& operator= (PA& that) { 38 if (&that != this) 39 reset (that.release ()); 40 return *this; 41 } 42 private: 43 A* release (void) { 44 A* p = m_p; 45 m_p = NULL; 46 return p; 47 } 48 void reset (A* p) { 49 if (p != m_p) { 50 delete m_p; 51 m_p = p; 52 } 53 } 54 A* m_p; 55 }; 56 void bar (auto_ptr<A> pa) { 57 cout << "bar:"; 58 pa -> hello (); 59 } 60 void foo (void) { 61 PA pa (new A); 62 // A* pa = new A; 63 // pa -> hello (); 64 // (*pa).hello (); 65 // A* pb = pa; 66 pa -> hello (); // pa.operator->()->hello(); 67 (*pa).hello (); // pa.operator*().hello(); 68 PA pb = pa; 69 pb -> hello (); 70 auto_ptr<A> pa1 (new A); 71 pa1 -> hello (); 72 auto_ptr<A> pa2 = pa1; 73 (*pa2).hello (); 74 bar (pa2); 75 cout << pa2.get () << endl; 76 } 77 // smart_ptr 78 int main (void) { 79 foo (); 80 return 0; 81 }
4.自定义类型转换和类型转换操作符
1)通过定义单参构造实现自定义类型转换
如果A类中有一个可以接受B类对象做为唯一参数的构造函数,那么B类型的对象就可以根据该构造函数被隐式转换为A类型。所以我们可以通过定义"单参构造函数"的方式实现自定义类型转换,而且是隐式的转换哦!
1 /* 2 * 举例: 3 */ 5 class A { 7 public: 9 A(); 11 A(B); // 单参构造 13 }; 14 15 int main() 17 { 19 A a; 21 B b; 23 a = b; // =左操作数是A类型,右操作数是B类型,但是A类型有B类型形参的"单参构造",所以b可以隐式的转换为A类型。 24 return 0; 25 }
但是有些场景我们要防止这样的隐式类型转换,可以通过给单参构造函数前加explicit关键字,强制要求所有使用了该构造函数所完成的类型转换必须显示进行。
1 class A { 2 public: 3 A(); 4 explicit A(B); // 带有explicit的单参构造 5 }; 6 7 int main() 8 { 9 A a; 10 B b; 11 //a = b; //ERROR. =左操作数是A类型,右操作数是B类型,A类型有B类型形参的"单参构造",但是有explicit关键字! 12 a = A(b); //OK. b必须显式的转换为A类型。 13 // 有木有突然明白C++规范里面一开始就说要支持了强制类型转换的写法从C语言里面的(int) a 格式转换为 int(a)格式了。 14 return 0; 15 }
2)通过定义类型转换操作符函数实现自定义类型转换
如果A类中有一个形如
operator B (void) const { ... }
的(无返回值类型)操作符函数,那么A类型的对象就可以根据该函数被转换为B类型。
1 /* 举例一: 2 * 有Integer i_integer(10); 和int n = 0; 3 * 那么要实现n = i_integer; 4 * 就需要在源类型中定义以目标类型为函数名称的类型转换操作符函数实现类型转换。 5 */ 6 #include <iostream> 7 class Integer{ 8 public: 9 explicit Integer(int i = 0) : m_n(i) {} 10 ~Integer(void) {} 11 12 //和构造/析构函数一样 类型转换操作符函数也没有返回值类型 13 operator int (void) const //类型转换操作符函数 14 { 15 return m_n; 16 } 17 18 private: 19 int m_n; 20 }; 21 22 int main() 23 { 24 Integer i_integer(10); 25 int n = 0; 26 n = i_integer;//编译器编译时候按照i_integer.operator int()调用 27 28 return 0; 29 }
1 /* 举例二: 2 * 自定义类型转换(重载类型转换操作符)举例 3 * */ 4 #include <iostream> 5 #include <cstring> 6 using namespace std; 7 class String { 8 public: 9 String (const char* str = NULL) { 10 m_str = new char[strlen(str?str:"")+1]; 11 strcpy (m_str, str ? str : ""); 12 } 13 ~String (void) { 14 if (m_str) { 15 delete[] m_str; 16 m_str = NULL; 17 } 18 } 19 String (const String& that) : 20 m_str (strcpy ( 21 new char[strlen(that.m_str)+1], 22 that.m_str)) {} 23 /* 菜鸟 24 void operator= (const String& that) { 25 m_str = new char[strlen(that.m_str)+1]; 26 strcpy (m_str, that.m_str); 27 }*/ 28 String& operator= (const String& that) { 29 if (&that != this) { 30 /* 小鸟 31 delete[] m_str; 32 m_str = new char[strlen(that.m_str)+1]; 33 strcpy (m_str, that.m_str); 34 */ 35 /* 大鸟 36 char* str = 37 new char[strlen(that.m_str)+1]; 38 delete[] m_str; 39 m_str = strcpy (str, that.m_str); 40 */ 41 // 老鸟 42 String temp (that); 43 swap (m_str, temp.m_str); 44 } 45 return *this; 46 } 47 const char* c_str (void) const { 48 return m_str; 49 } 50 operator const char* (void) const {//这里自定义了类型转换操作符函数,实现了从String转换为char*的类型转换 51 return c_str (); 52 } 53 private: 54 char* m_str; 55 }; 56 int main (void) { 57 String s1 ("Hello, World !"); 58 cout << s1.c_str () << endl; 59 String s2 = s1; 60 cout << s2.c_str () << endl; 61 String s3 ("Hello, Linux !"); 62 try { 63 s1 = s3; 64 } 65 catch (exception& ex) { 66 cout << ex.what () << endl; 67 } 68 cout << s1.c_str () << endl; 69 const char* psz = s1; 70 cout << s1 << endl; 71 cout << psz << endl; 72 return 0; 73 }
总结:如果目标类型是类类型,源类型是基本类型,那么就只能通过在目标类型中定义以源类型为单一形参的构造函数(单参构造)实现类型转换。如果目标类型是基本类型,源类型 是类类型,那么就只能通过在源类型中定义以目标类型为函数名的类型转换操作符函数实现类型转换。如果目标类型和源类型都是类类型,那么以上两种方法任取其 一,但是不能同时使用。如果目标类型和源类型都是基本类型,那么无法实现自定义类型转换。
5.new/delete操作符
/*new/delete操作符重载例程*/
1 /*new/delete操作符重载例程*/ 2 #include <iostream> 3 #include <cstdlib> 4 using namespace std; 5 class A { 6 public: 7 ~A (void) {} 8 static void* operator new (size_t size) { 9 void* p = malloc (size); 10 cout << "我的new :" << p << ‘ ‘ 11 << size << endl; 12 return p; 13 } 14 static void operator delete (void* p) { 15 cout << "我的delete:" << p << endl; 16 free (p); 17 } 18 static void* operator new[] (size_t size) { 19 void* p = malloc (size); 20 cout << "我的new[] :" << p << ‘ ‘ 21 << size << endl; 22 return p; 23 } 24 static void operator delete[] (void* p) { 25 cout << "我的delete[]:" << p << endl; 26 free (p); 27 } 28 private: 29 int m_i; 30 double m_d; 31 char m_c; 32 }; //Class A占有的存储空间大小是16byte,形如 IIIIDDDDDDDDCXXX 33 34 int main (void) { 35 cout << sizeof (A) << endl; 36 A* pa = new A;//A::operator new(sizeof(A)); 37 cout << pa << endl; 38 delete pa; 39 pa = new A[2];//A::operator new(sizeof(A[2])); 40 cout << pa << endl; 41 delete[] pa;//如果不用delete[] pa;而用delete pa;会造成操作系统吐核。 42 return 0; 43 }
五、关于操作符重载的限制
1.至少有一个操作数是类类型的。
/*ERROR
至少有一个操作数是类类型的*/
int a = 10, b = 20;
int c = a + b; // 200
int operator+ (int a, int b) {
return a * b;
} // ERROR !
2.不是所有的操作符都能重载。
:: - 作用域限定
. - 成员访问操作符
.* - 成员指针解引用
?: - 三目运算符
sizeof - 获取字节数(p.s.sizof(表达式)在编译期就被编译器处理了,sizof(表达式)计算结果是表达式的类型的占有空间大小)
typeid - 获取类型信息
3.不是所有的操作符都可以用全局函数的方式实现。
= - 拷贝赋值
[] - 下标
() - 函数
-> - 间接访问操作符
4.不能发明新的操作符,不能改变操作数的个数。
x ** y; // x^y
#
@
*
1 // 操作符重载练习一 2 // 3 // 日期运算。 4 // 实现日期类,支持如下运算: 5 // +/+=:增加指定的天数; 6 // -/-=:减去指定的天数; 7 // - :两日期相差天数。 8 // >> :接受形如2014 1 14格式输入; 9 // << :以形如2014-1-14的格式输出; 10 #include <iostream> 11 using namespace std; 12 class Date { 13 public: 14 Date (int nYear = 0, int nMonth = 0, 15 int nDay = 0) : 16 m_nYear (nYear), m_nMonth (nMonth), 17 m_nDay (nDay) {} 18 Date operator+ (int nDays) const { 19 return Days2Date (Date2Days () + nDays); 20 } 21 Date& operator+= (int nDays) { 22 return *this = *this + nDays; 23 } 24 Date operator- (int nDays) const { 25 return Days2Date (Date2Days () - nDays); 26 } 27 Date& operator-= (int nDays) { 28 return *this = *this - nDays; 29 } 30 int operator- (const Date& date) const { 31 return Date2Days () - date.Date2Days (); 32 } 33 friend istream& operator>> (istream& is, 34 Date& date) { 35 return is >> date.m_nYear >> date.m_nMonth 36 >> date.m_nDay; 37 } 38 friend ostream& operator<< (ostream& os, 39 const Date& date) { 40 return os << date.m_nYear << "-" 41 << date.m_nMonth << "-" << date.m_nDay; 42 } 43 private: 44 int Date2Days (void) const { 45 int nDays = (m_nYear - 1) * 365; 46 for (int nYear = 1; nYear < m_nYear; 47 nYear++) 48 if (IsLeap (nYear)) 49 nDays++; 50 for (int nMonth = 0; nMonth < m_nMonth - 1; 51 nMonth++) 52 if (IsLeap (m_nYear)) 53 nDays += s_nDaysOfMonth[1][nMonth]; 54 else 55 nDays += s_nDaysOfMonth[0][nMonth]; 56 nDays += m_nDay; 57 return nDays; 58 } 59 Date Days2Date (int nDays) const { 60 int nYear = 1; 61 for (;;) { 62 if (IsLeap (nYear)) { 63 if (nDays <= 366) 64 break; 65 nDays -= 366; 66 } 67 else { 68 if (nDays <= 365) 69 break; 70 nDays -= 365; 71 } 72 nYear++; 73 } 74 int nMonth = 1; 75 bool bLeap = IsLeap (nYear); 76 for (;;) { 77 if (bLeap) { 78 if (nDays <= 79 s_nDaysOfMonth[1][nMonth-1]) 80 break; 81 nDays-=s_nDaysOfMonth[1][nMonth-1]; 82 } 83 else { 84 if (nDays <= 85 s_nDaysOfMonth[0][nMonth-1]) 86 break; 87 nDays-=s_nDaysOfMonth[0][nMonth-1]; 88 } 89 nMonth++; 90 } 91 return Date (nYear, nMonth, nDays); 92 } 93 bool IsLeap (int nYear) const { 94 return (nYear % 4 == 0 && nYear % 100 != 0) 95 || nYear % 400 == 0; 96 } 97 int m_nYear; 98 int m_nMonth; 99 int m_nDay; 100 static int s_nDaysOfMonth[][12]; 101 }; 102 int Date::s_nDaysOfMonth[][12] = { 103 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31}, 104 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30,31} 105 }; 106 int main (void) { 107 cout << "Enter a date: "; 108 Date d1; 109 cin >> d1; 110 cout << "Enter the number of days: "; 111 int nDays; 112 cin >> nDays; 113 Date d2 = d1 + nDays; 114 cout << d1 << " + " << nDays << " = " << d2 115 << endl; 116 Date d3 (d1); 117 d3 += nDays; 118 cout << d1 << " += " << nDays << " -> " << d3 119 << endl; 120 cout << "Enter a date: "; 121 cin >> d1; 122 cout << "Enter the number of days: "; 123 cin >> nDays; 124 d2 = d1 - nDays; 125 cout << d1 << " - " << nDays << " = " << d2 126 << endl; 127 d3 = d1; 128 d3 -= nDays; 129 cout << d1 << " -= " << nDays << " -> " << d3 130 << endl; 131 cout << "Enter a date: "; 132 cin >> d1; 133 cout << "Enter another date: "; 134 cin >> d2; 135 cout << "The days between those dates is " 136 << d2 - d1 << endl; 137 return 0; 138 }
1 // 2 // 3 //操作符重载练习二 4 // 5 // 6 #include <iomanip> 7 #include <iostream> 8 using namespace std; 9 class M33 { 10 public: 11 M33 (void) { 12 for (int i = 0; i < 3; i++) 13 for (int j = 0; j < 3; j++) 14 m_a[i][j] = 0; 15 } 16 M33 (int a[][3]) { 17 for (int i = 0; i < 3; i++) 18 for (int j = 0; j < 3; j++) 19 m_a[i][j] = a[i][j]; 20 } 21 const M33 operator+ (const M33& m) const { 22 int a[3][3]; 23 for (int i = 0; i < 3; i++) 24 for (int j = 0; j < 3; j++) 25 a[i][j] = m_a[i][j] + m.m_a[i][j]; 26 return a; 27 } 28 const M33 operator- (const M33& m) const { 29 int a[3][3]; 30 for (int i = 0; i < 3; i++) 31 for (int j = 0; j < 3; j++) 32 a[i][j] = m_a[i][j] - m.m_a[i][j]; 33 return a; 34 } 35 const M33 operator* (const M33& m) const { 36 int a[3][3] = {0}; 37 for (int i = 0; i < 3; i++) 38 for (int j = 0; j < 3; j++) 39 for (int k = 0; k < 3; k++) 40 a[i][j]+=m_a[i][k]*m.m_a[k][j]; 41 return a; 42 } 43 M33& operator+= (const M33& m) { 44 return *this = *this + m; 45 } 46 M33& operator-= (const M33& m) { 47 return *this = *this - m; 48 } 49 M33& operator*= (const M33& m) { 50 return *this = *this * m; 51 } 52 const M33 operator- (void) const { 53 return M33 () - *this; 54 } 55 M33& operator++ (void) { 56 for (int i = 0; i < 3; i++) 57 for (int j = 0; j < 3; j++) 58 m_a[i][j]++; 59 return *this; 60 } 61 M33& operator-- (void) { 62 for (int i = 0; i < 3; i++) 63 for (int j = 0; j < 3; j++) 64 m_a[i][j]--; 65 return *this; 66 } 67 const M33 operator++ (int) { 68 M33 m = *this; 69 ++(*this); 70 return m; 71 } 72 const M33 operator-- (int) { 73 M33 m = *this; 74 --(*this); 75 return m; 76 } 77 friend ostream& operator<< (ostream& os, 78 const M33& m) { 79 for (int i = 0; i < 3; i++) { 80 for (int j = 0; j < 3; j++) 81 os << setw (4) << m.m_a[i][j]; 82 os << endl; 83 } 84 return os; 85 } 86 private: 87 int m_a[3][3]; 88 }; 89 int main (void) { 90 int a1[3][3] = {1,2,3,4,5,6,7,8,9}; 91 M33 m1 (a1); 92 int a2[3][3] = {9,8,7,6,5,4,3,2,1}; 93 M33 m2 (a2); 94 cout << m1 + m2 << endl; 95 cout << m1 - m2 << endl; 96 cout << m1 * m2 << endl; 97 m1 += m2; 98 cout << m1 << endl; 99 m1 -= m2; 100 cout << m1 << endl; 101 m1 *= m2; 102 cout << m1 << endl; 103 cout << -m1 << endl; 104 cout << ++m2 << endl; 105 cout << m2 << endl; 106 cout << --m2 << endl; 107 cout << m2 << endl; 108 cout << m2++ << endl; 109 cout << m2 << endl; 110 cout << m2-- << endl; 111 cout << m2 << endl; 112 return 0; 113 }
标签:
原文地址:http://www.cnblogs.com/libig/p/4746692.html