1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 //平面向量类,提供完成向量运算和比较的API 6 //除递增运算符和左移运算符重载外其他函数省略 7 8 class Vec2D 9 { 10 //形参cout和函数返回值使用引用是为了保证拷贝构造函数的调用,以确保全局cout对象唯一 11 //形参vec使用引用是为了提高函数调用效率,也可以不用 12 friend ostream& operator<<(ostream& cout, Vec2D& v); //重载<<运算符 13 14 public: 15 Vec2D(double x, double y); //有参构造函数 16 Vec2D& operator++(); //重载前置++运算符 17 Vec2D operator++(int); //重载后置++运算符 18 19 private: 20 double _x; 21 double _y; 22 23 }; 24 25 ostream& operator<<(ostream& cout, Vec2D& v) 26 { 27 cout << '(' << v._x << ',' << v._y << ')' << endl; 28 return cout; 29 } 30 31 Vec2D::Vec2D(double x, double y) 32 { 33 _x = x; 34 _y = y; 35 } 36 37 Vec2D& Vec2D::operator++() 38 { 39 this->_x++; 40 this->_y++; 41 return *this; 42 } 43 44 Vec2D Vec2D::operator++(int) 45 { 46 Vec2D pre = *this; 47 this->_x++; 48 this->_y++; 49 return pre; 50 } 51 52 void test01() 53 { 54 Vec2D v1{ 1, 1 }; 55 cout << ++v1 << endl; 56 //cout << v1++ << endl; 57 } 58 59 int main() 60 { 61 test01(); 62 return 0; 63 }
我在初学时遇到的一个问题是:重载后置++运算符时,应不应当返回对象的引用?
首先须明确,若令pre = *this,返回引用一定是错误的,因为这是一个开辟在栈内的局部对象,生命周期在成员函数内部,函数结束内存就被释放了;而引用本质是利用指针常量操作对象,利用指针操作不存在的内存是危险的。
其次,若想返回引用,须使用pre = new Vec2D(this->_x, this->_y),这是开辟在堆内的,因此可以安全返回其地址。但与之而来的问题是后续无法对其delete,容易造成内存泄漏。
因此,直接返回对象本身最为妥当,尽管会因此隐式调用一次拷贝构造函数。
与之而来的是第二个问题:代码中注释掉的一行cout << v1++ << endl,会报错:“没有与这些操作数匹配的‘<<’运算符”。
这是因为在定义<<重载时为了提高函数调用运行效率传递对象时,采取了传址调用(引用),而既然需要解引用,就要求实参必须是可以解引用的值,即左值;
而后置++运算符重载返回了一个局部对象,这是一个右值,不能作为左值,所以会报错;
修改方法有二:
(1)把<<运算符重载的形参v修改为传值调用,这样既可以传入一个右值了;
(2)在形参前加上const修饰,即:
friend ostream& operator<<(ostream& cout, const Vec2D& v);
这是因为当const
修饰一个左值引用(型如const Type &
)时,表示该左值引用既可以引用一个左值,也可以引用一个右值(字面值或临时对象),而不带 const
修饰的左值引用(型如Type &
)只能引用一个左值,不能引用一个右值。