C++学习笔记之运算符重载
双目运算符:
1 #include <iostream> 2 using namespace std; 3 class Complex { 4 public: 5 Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { } //默认构造函数虽说是默认,但是如果给了参数也能调用,是一个好习惯 6 7 Complex operator+(const Complex& c2) const;//+ 8 9 Complex operator+(int& a) const;//复数和实数 10 11 Complex operator - (const Complex& c2) const;//- 12 13 void display() const; //输出复数 14 private: 15 double real; //复数实部 16 double imag; //复数虚部 17 }; 18 19 Complex Complex::operator +(const Complex & c2) const { //复数+ 20 return Complex(real + c2.real, imag + c2.imag); 21 } 22 23 Complex Complex::operator +(int& a) const {//复数和实数+ 24 a++; 25 return Complex(real + a, imag ); 26 } 27 28 Complex Complex::operator-(const Complex& c2) const {//复数- 29 return Complex(real - c2.real, imag - c2.imag); 30 } 31 32 void Complex::display() const { 33 cout << "(" << real << ", " << imag << ")" << endl; 34 } 35 36 int main() { 37 Complex c1(5, 4), c2(2, 10), c3; 38 int b = 5; 39 cout << "c1 = "; c1.display(); 40 cout << "c2 = "; c2.display(); 41 c3 = c1 - c2; //使用重载运算符完成复数减法 42 cout << "c3 = c1 - c2 = "; c3.display(); 43 c3 = c1 + c2; //使用重载运算符完成复数加法 44 cout << "c3 = c1 + c2 = "; c3.display(); 45 c3 = c1 + b; //这里是复数和实数相加,注意(复数和int变量相加)和(复数直接加数c3=c1+5)的区别,后者编译器会把 5 当成复数再次生成一个复数类的对象,但是只有一个参数,也就是实部,然后进行复数类相加
,原因是写了默认的构造函数(上面黄色),我怀疑是加法函数的顺序问题,但试了一下,发现并不是,终究还是构造函数的问题,下面会给出后面这种方式的代码 46 cout << "c3 = c1 + c2 = "; c3.display(); 47 return 0; 48 }
想要让 c3=c1+5 调用的函数是复数+实数的代码(黄色是不用的地方):
1 #include <iostream> 2 using namespace std; 3 class Complex { 4 public: 5 Complex() {};//默认构造函数,并不初始化赋值 6 Complex(double r, double i) : real(r), imag(i) { } 7 8 Complex operator+(const Complex& c2) const;//+ 9 10 Complex operator+(int a) const;//复数和实数 11 12 Complex operator - (const Complex& c2) const;//- 13 14 void display() const; //输出复数 15 private: 16 double real; //复数实部 17 double imag; //复数虚部 18 }; 19 20 Complex Complex::operator +(const Complex & c2) const { //复数+ 21 return Complex(real + c2.real, imag + c2.imag); 22 } 23 24 Complex Complex::operator +(int a) const {//复数和实数+ 25 a++; 26 return Complex(real + a, imag ); 27 } 28 29 Complex Complex::operator-(const Complex& c2) const {//复数- 30 return Complex(real - c2.real, imag - c2.imag); 31 } 32 33 void Complex::display() const { 34 cout << "(" << real << ", " << imag << ")" << endl; 35 } 36 37 int main() { 38 Complex c1(5, 4), c2(2, 10), c3;//c3 调用默认构造函数,垃圾数据 39 int b = 5; 40 cout << "c1 = "; c1.display(); 41 cout << "c2 = "; c2.display(); 42 c3 = c1 - c2; //使用重载运算符完成复数减法 43 cout << "c3 = c1 - c2 = "; c3.display(); 44 c3 = c1 + c2; //使用重载运算符完成复数加法 45 cout << "c3 = c1 + c2 = "; c3.display(); 46 c3 = c1 + 5; 47 cout << "c3 = c1 + c2 = "; c3.display(); 48 return 0; 49 }
虽然后面解决了这种问题,但是我也发现了这种直接通过对象 运算符重载计算 的漏洞,所以我强烈建议对象之间的操作不要直接通过数字,而是通过对象和对象的操作从而使得能够按照自己的想法运行,虽然直接通过数字可以,但是其构造函数明显是不合理的(因为默认构造函数并没有给默认参数,而是垃圾数据,C3就是例子)
为了解决这种情况,我们提出了非成员函数解决这个问题(之前的方法是调用成员函数)那这两种方法有什么区别?
如果要重载 B 为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2),这里形参少一个,因为这个类的对象就是其中一个操作数
而在非成员函数中:参数个数=原操作数个数,表达式oprd1 B oprd2,等同于operator B(oprd1,oprd2 ),因为并不是成员函数,所以只是返回的类型是这个类型,而形参表中首先必须要有自定义的类型,就像调用一个函数一样
如果在运算符的重载函数中需要操作某类对象的私有成员,可以将此函数声明为该类的友元。