书上代码
#include<iostream>
#include<cassert>
using namespace std;
class Point{
public:
Point():x(0),y(0){
cout<<"Default Constructor called"<<endl;
}
Point(int x, int y):x(x), y(y){
cout<<"Constructor called"<<endl;
}
~Point(){
cout<<"Destructor called"<<endl;
}
int getX() const{return x;}
int getY() const{return y;}
void move(int newx,int newy){
x = newx;
y = newy;
}
private:
int x,y;
};
class ArrayOfPoints{
public:
ArrayOfPoints(int size):size(size){
points = new Point[size];
}
~ArrayOfPoints(){
cout<<"Deleting......";
delete []points;
}
Point element(int index){
assert(index >= 0 && index < size);
return points[index];
}
private:
Point *points;
int size;
};
int main()
{
int num;
cout<<"请输入要动态创建的个数:"<<endl;
cin>>num;
ArrayOfPoint Point(num);
Point.Element(0).Move(5,4);
Point.Element(1).Move(65,99);
return 0;
}
其中Point & element(int)中的&让人很是费解
首先复习一下&(引用)的作用,是按照地址返回值,这是一个类似指针但又不同于指针的的操作,指针返回的是地址,它返回的是值,但说类似是因为它所返回的值是实实在在的原地址的那个值,而不是从那个值复制而来的另一个不同地址但却相等的另一个值。
这样我们可以改写一下代码
#include<iostream>
#include<cassert>
#include<cstdlib>
using namespace std;
class Point{
public:
Point():x(0),y(0){
cout<<"Default Constructor called"<<endl;
}
Point(int x, int y):x(x), y(y){
cout<<"Constructor called"<<endl;
}
Point(Point &point):x(point.x), y(point.y){
cout<<"is cpoying"<<endl;
}
~Point(){
cout<<"Destructor called"<<endl;
}
int getX() const{return x;}
int getY() const{return y;}
void move(int newx,int newy){
x = newx;
y = newy;
}
private:
int x,y;
};
class ArrayOfPoints{
public:
ArrayOfPoints(int size):size(size){
points = new Point[size];
}
~ArrayOfPoints(){
cout<<"Deleting......";
delete []points;
}
Point element(int index){
assert(index >= 0 && index < size);
return points[index];
}
private:
Point *points;
int size;
};
int main(){
int count;
count = 2;
ArrayOfPoints pointsArray1(count);
pointsArray1.element(0).move(5,10);
pointsArray1.element(1).move(15,20);
cout<<pointsArray1.element(0).getX()<<" "<<pointsArray1.element(0).getY()<<endl;
cout<<pointsArray1.element(1).getX()<<" "<<pointsArray1.element(0).getY()<<endl;
system("pause");
return 0;
}
代码在原有基础上新加入了复制构造函数,并且执行复制构造函数时会输出is copying,并且我们还会新输出move后的x,y的值。
先执行一次加上&的版本
Default Constructor called
Default Constructor called
5 10
15 10
Press any key to continue . . .
我们可以发现,和初始代码结果差不多(只增加了move后俩点的坐标,(5,10)和(15,10),并且符合我们的认知)。
我们再执行一次去掉&后的版本`
Default Constructor called
Default Constructor called
is cpoying
Destructor called
is cpoying
Destructor called
is cpoying
0 is cpoying
0
Destructor called
Destructor called
is cpoying
0 is cpoying
0
Destructor called
Destructor called
Press any key to continue . . .
很明显,这次多了几句is copying(执行复制构造函数)和Destructor called(执行析构函数)。并且move后的俩点的坐标均是(0,0),即默认创建Point对象的初始值(不信你可以换着试试)
再让我们来分析分析原因:
这涉及函数的相关知识,函数再返回一个值的时候(假设此值与地址无关,即不是地址,指针,引用),那么会生成一个副本,让这个副本临时存储函数执行的结果,然后再将这个副本复制给相关变量,所以,无&的时候就会多执行复制构造函数,析构函数(删除副本)。这就是会出现如此多的复制构造函数和析构函数的原因。并且无法使用move对Point[index]造成影响,因为你move的只是副本传出的值而非原始地址的那个值,故你再次使用Point elment(int)函数时,他会重新生成副本Point,且这个Point的x,y均为0。
加上&后就可以避免以上问题了。
改版后的代码无&会在三处造成影响,1:执行Point elment(int)时,2:执行move()时,3:执行getX()时,(执行getY()时用的是执行getX()的那个Point,故不造成影响)。