C++构造函数、复制函数易错点
C++中复制函数在三种情况下自动调用:
- 用一个对象初始化另一个对象
- 函数的参数为对象
- 函数的返回值为对象
下面用几个代码片段解释复制函数的调用中的一些常见“坑”:
一:默认复制函数的自动调用
1 #include<iostream> 2 using namespace std; 3 4 class Point 5 { 6 public: 7 Point(int X, int Y) :x(X), y(Y) {}; 8 void showCoordinate() 9 { 10 //展示坐标 11 cout << "X=" << x << "\tY=" << y << endl; 12 } 13 private: 14 int x; 15 int y; 16 }; 17 18 int main() 19 { 20 Point p1(0, 0); 21 p1.showCoordinate(); 22 Point p2 = p1; //此事并未编写显示的复制函数,系统会自动生成Point的一个自适应复制函数 23 p2.showCoordinate(); //发现 p2 的坐标与 p1 相同 24 cout << &p1 << endl; 25 cout << &p2 << endl; //显然,p2 只是 p1 复制函数之后的新的对象,在内存中的地址并不相同 26 return 0; 27 }
二:不存在合适的构造函数【实质上还是复制函数的问题】
#include<iostream> using namespace std; class Point { public: Point(int X, int Y) :x(X), y(Y) {}; Point(Point& p); int getX() { return x; } int getY() { return y; } private: int x; int y; }; Point::Point(Point& p) { x = p.x; y = p.y; } class Line { public: Line(Point temp_p1, Point temp_p2) { p1 = temp_p1; p2 = temp_p2; }; private: Point p1; Point p2; }; int main() { Point p1(0, 0); Point p2 = p1; //此时复制函数仍然可以正常调用,但是 24 行报错 /** * C2512“Point” : 没有合适的默认构造函数可用 * E0291 类 "Point" 不存在默认构造函数 */ return 0; }
为什么出现这种情况,实质上是因为1:Line的构造函数中使用了无参数的构造函数,但是只有当没有编写构造函数时,系统会自动生成一个没有参数的构造函数,而编写了构造函数之后系统并不会自动生成。
一个治标不治本的方法是,在class Point中加入一个无参数的构造函数。但是问题显而易见,么有参数的构造函数并么有实际意义。所以只能通过类的组合,将Point类内嵌在Line类中。
将其改为:
至此,可以编写计算线段长度的程序:
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 5 class Point 6 { 7 public: 8 Point(int X, int Y) :x(X), y(Y) {}; 9 Point(Point& p); 10 int getX() { return x; } 11 int getY() { return y; } 12 private: 13 int x; 14 int y; 15 }; 16 Point::Point(Point& p) { 17 x = p.x; 18 y = p.y; 19 } 20 class Line 21 { 22 public: 23 Line(Point temp_p1, Point temp_p2) : p1(temp_p1), p2(temp_p2) {}; 24 double getLen(); 25 private: 26 Point p1; 27 Point p2; 28 }; 29 30 //计算线段长度,比较简单,可以设置为内联 31 inline double Line::getLen() 32 { 33 int a = abs(p1.getX() - p2.getX()); 34 int b = abs(p1.getY() - p2.getY()); 35 double len = sqrt(a * a + b * b); 36 return len; 37 } 38 39 int main() 40 { 41 Point p1(0, 0); 42 Point p2(3, 4); 43 Line line1(p1, p2); 44 cout << line1.getLen() << endl; //输出线段长度 45 46 47 return 0; 48 }