C++面向对象程序设计的一些知识点(5)
摘要:运算符能给程序员提供一种书写数学公式的感觉,本质上运算符也是一种函数,因此有类内部运算符和全局运算符之分,通过重载,运算符的“动作”更加有针对性,编写代码更像写英文文章。
1、C++标准允许将运算符重载为类成员或者全局的,一般如果是全局的话,为了效率,都是把它们定义为类友元函数。
1 /* 2 ** 重载全局运算符“+”、“-”,代码如下: 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 //class Complex; 9 //Complex operator+(const Complex &c1, const Complex &c2); 10 //Complex operator-(const Complex &c1, const Complex &c2); 11 // 我的疑问:声明为全局的有什么好处的,或者说有什么必要的么? 12 class Complex 13 { 14 public: 15 Complex(double real = 0.0, double image = 0.0) 16 { 17 this->real = real; 18 this->image = image; 19 } 20 public: 21 void displayComplex() 22 { 23 if(image >= 0) 24 cout << "(" << real << '+' << image << 'i' << ")"; 25 else 26 cout << "(" << real << image << 'i' << ")"; 27 } 28 friend Complex operator+(const Complex &c1, const Complex &c2); 29 friend Complex operator-(const Complex &c1, const Complex &c2); 30 private: 31 double real; 32 double image; 33 }; 34 35 Complex operator+(const Complex &c1, const Complex &c2) 36 { 37 Complex complexTemp; 38 complexTemp.real = c1.real + c2.real; 39 complexTemp.image = c1.image + c2.image; 40 return complexTemp; 41 } 42 Complex operator-(const Complex &c1, const Complex &c2) 43 { 44 Complex complexTemp; 45 complexTemp.real = c1.real - c2.real; 46 complexTemp.image = c1.image - c2.image; 47 return complexTemp; 48 } 49 int main() 50 { 51 Complex c, c1(1.1, 2.2), c2(3.3, 4.4); 52 c = c1 + c2; 53 c = c1 - c2; // operator-(c1, c2); 54 c1.displayComplex(); 55 cout << "-"; 56 c2.displayComplex(); 57 cout << "="; 58 c.displayComplex(); 59 cout << endl; 60 61 int i; 62 cin >> i; 63 return 0; 64 }
2、运算符重载的一些基本规则:
禁止用户发明C++语言运算符之外的其他运算符
不要试图改变重载运算符的语义,保持重载后的运算语义与内置运算符语义一致,否则会带来思维上的混乱
不能重载.、.*、::、?:
不能重载#、##
不能重载sizeof()、typeid()
不能重载static_cast<>、dynamic_cast<>、const_cast<>、reinterpret_cast<>
3、运算符重载时,它的返回值类型会有程序运行效率和使用重载运算符方便程度的差别
当返回值为对象时,拷贝构造函数会构建一个临时对象
当返回值为对象引用时,不会引起构造函数的调用,其返回值可以作为左值
当返回值为对象指针时,不会引发构造函数的调用,其返回值可以作为左值
1 /* 2 ** 重载运算符,返回不同类型的差别 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 class Complex 9 { 10 public: 11 Complex(double real = 0.0, double image = 0.0) 12 { 13 this->real = real; 14 this->image = image; 15 } 16 Complex(const Complex &c) // 拷贝构造函数 17 { 18 real = c.real; 19 image = c.image; 20 cout << "copy constructing..." << endl; 21 } 22 public: 23 Complex operator+(const Complex &c) 24 { 25 Complex complexTemp; 26 complexTemp.real = real + c.real; 27 complexTemp.image = image + c.image; 28 return complexTemp; // 此时会调用拷贝构造函数,构造一个临时对象 29 } 30 Complex& operator-(const Complex &c) 31 { 32 real -= c.real; 33 image -= c.image; 34 return *this; 35 } 36 void displayComplex() 37 { 38 if(image >= 0) 39 cout << "(" << real << "+" << image << "i" << ")"; 40 else 41 cout << "(" << real << image << "i" << ")"; 42 } 43 private: 44 double real; 45 double image; 46 }; 47 int main() 48 { 49 Complex c, c1(1.1, 2.2), c2(3.3, 4.4); 50 (c1 + c2).displayComplex(); 51 cout << "Before c1 - c2" << endl; 52 c1.displayComplex(); 53 cout << endl; 54 cout << "After c1 - c2" << endl; 55 (c1 - c2).displayComplex(); 56 cout << endl; 57 int i; 58 cin >> i; 59 return 0; 60 }
4、运算符重载示例:
赋值运算符
1 /* 2 ** 赋值运算符“=”重载 3 */ 4 #include <iostream> 5 #include <cstring> 6 7 using namespace std; 8 9 class Student 10 { 11 public: 12 Student(char *name = "") 13 { 14 pName = new char[strlen(name) + 1]; 15 strcpy(pName, name); 16 } 17 ~Student() 18 { 19 delete pName; 20 pName = NULL; 21 } 22 public: 23 Student &operator=(const Student &student) 24 { 25 cout << "assignment called..." << endl; 26 // 若为同一个对象则直接返回即可 27 if(this == &student) // 注意这里需要用指针比较,因为没有实现对象比较的运算符呢 28 { 29 cout<< "\tExact the same object." << endl; 30 return *this; 31 } 32 delete pName; // 否则,先释放资源 33 pName = new char[strlen(student.pName) + 1]; 34 strcpy(pName, student.pName); 35 return *this; 36 } 37 void show() 38 { 39 cout << pName << endl; 40 } 41 private: 42 char *pName; 43 }; 44 45 int main() 46 { 47 Student s1, s2("zhangsan"); 48 s1 = s1; 49 50 s1 = s2; 51 s1.show(); 52 53 int i; 54 cin >> i; 55 return 0; 56 }
函数符
1 /* 2 ** 函数符“()”重载 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 class Student 9 { 10 public: 11 Student(int chinese, int math, int english) 12 { 13 this->chinese = chinese; 14 this->math = math; 15 this->english = english; 16 } 17 ~Student() 18 { } 19 public: 20 void operator()(int index = 0) 21 { 22 switch(index) 23 { 24 case 0: 25 cout << "chinese:" << chinese << endl; 26 break; 27 case 1: 28 cout << "math:" << math << endl; 29 break; 30 case 2: 31 cout << "english:" << math << endl; 32 break; 33 default: 34 cout << "not found" << endl; 35 } 36 } 37 private: 38 int chinese; 39 int math; 40 int english; 41 }; 42 int main() 43 { 44 Student student(80, 90, 92); 45 student(); 46 student(0); 47 student(1); 48 student(2); 49 student(3); 50 student(4); 51 52 int i; 53 cin >> i; 54 return 0; 55 }
下标运算
1 /* 2 ** 下表运算符“[]”重载 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 class UserString 9 { 10 public: 11 UserString(char *str) 12 { 13 len = strlen(str); 14 this->str = new char[len + 1]; 15 strcpy(this->str, str); 16 } 17 ~UserString() 18 { 19 delete str; 20 str = NULL; 21 } 22 public: 23 char operator[](int index) 24 { 25 if(index >= 0 && index < len) // 判断越界 26 return str[index]; 27 else 28 { 29 cout << "beyond scope..." << endl; 30 return ' '; 31 } 32 } 33 int getLength() 34 { 35 return len; 36 } 37 private: 38 char *str; 39 int len; 40 }; 41 42 int main() 43 { 44 UserString us("zhangsan"); 45 cout << "\"zhangsan\" length:" << us.getLength() << endl; 46 int length = us.getLength(); 47 int i; 48 for(i = 0;i < length;i++) 49 cout << us[i]; // 使用[]访问 50 cout << endl; 51 cout << us[i]; 52 53 cin >> i; 54 return 0; 55 }
运算符++、--
1 /* 2 ** 运算符“++、--”重载 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 class Integer 9 { 10 public: 11 Integer(int data) 12 { 13 this->data = data; 14 } 15 Integer(const Integer &i) 16 { 17 this->data = i.data; 18 } 19 ~Integer() 20 { } 21 public: 22 Integer operator++(int) 23 { 24 Integer temp(*this); 25 data++; 26 return temp; 27 } 28 Integer operator++() 29 { 30 data++; 31 return *this; 32 } 33 void show() 34 { 35 cout << data << endl; 36 } 37 private: 38 int data; 39 }; 40 41 int main() 42 { 43 Integer x(1); 44 (x++).show(); 45 (++x).show(); 46 47 int i; 48 cin >> i; 49 return 0; 50 }
类型转换
1 /* 2 ** 类型转换运算符重载,从对象到内置类型 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 class Complex 9 { 10 public: 11 Complex(double real, double image) 12 { 13 this->real = real; 14 this->image = image; 15 } 16 public: 17 operator double() 18 { 19 return real; 20 } 21 private: 22 double real; 23 double image; 24 }; 25 26 int main() 27 { 28 double d = 1.1; 29 Complex c(4.0, 5.0); 30 31 d += c; // 此时c.operator double()返回4.0 32 cout << d << endl; 33 34 int i; 35 cin >> i; 36 return 0; 37 }
1 /* 2 ** 类型转换运算符重载,从内置类型到对象 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 class Complex 9 { 10 public: 11 Complex(double real, double image) 12 { 13 this->real = real; 14 this->image = image; 15 } 16 Complex(const Complex &c) 17 { 18 real = c.real; 19 image = c.image; 20 cout << "copy constructor called..." << endl; 21 } 22 Complex(double real) 23 { 24 this->real = real; 25 this->image = 0; 26 cout << "one parameter called..." << endl; 27 } 28 ~Complex() 29 {} 30 public: 31 Complex& operator+=(const Complex &c) 32 { 33 real += c.real; 34 image += c.image; 35 cout << "overload operator+= called..." << endl; 36 return *this; 37 } 38 void show() 39 { 40 cout << real; 41 if(image >= 0) 42 cout << "+" << image << "i" << endl; 43 else 44 cout << image << "i" << endl; 45 } 46 private: 47 double real; 48 double image; 49 }; 50 51 int main() 52 { 53 Complex c1(0, 1.1); 54 c1 += 3.3; 55 c1.show(); 56 57 int i; 58 cin >> i; 59 return 0; 60 }
5、运算符重载规则
运算符 | 规则 |
所有单目运算符 | 建议重载为非static成员函数 |
=、()、[]、->、* | 建议重载为非static成员函数 |
+=、-=、/=、*=、&=、|=、~=、%=、>>=、<<= | 建议重载为非static成员函数 |
所有其他运算符 | 建议重载为全局函数或类的友元函数 |