注意:本文中代码均使用 Qt 开发编译环境
//“浅拷贝”举例:
#include <QCoreApplication>
#include <QDebug>
class Point
{
public:
Point(){
X=Y=0;
qDebug() << "Default Constructor called.";
}
Point(int xx,int yy){
X=xx;
Y=yy;
qDebug() << "Constructor called.";
}
~Point(){
qDebug() << "Destructor called.";
}
int GetX() const {
return X;
}
int GetY() const {
return Y;
}
void Move(int x,int y){
X=x;
Y=y;
}
private:
int X,Y;
};
class ArrayOfPoints
{
public:
ArrayOfPoints(int n){
numberOfPoints = n;
points = new Point[n];
}
~ArrayOfPoints(){
qDebug() << "Deleting...";
numberOfPoints = 0;
delete [] points;
}
Point& Element(int n){
return points[n];
}
private:
Point *points;
int numberOfPoints;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int number = 64;
ArrayOfPoints pointArray1(number); // 创建对象数组
pointArray1.Element(0).Move(5,10); // 通过指针访问数组元素的成员
pointArray1.Element(1).Move(15,20); // 通过指针访问数组元素的成员
ArrayOfPoints pointArray2(pointArray1); // 创建对象数组副本
qDebug() << "Copy of pointsArray1: ";
qDebug() << "Point_0 of array2: " << pointArray2.Element(0).GetX() << "," << pointArray2.Element(0).GetY();
qDebug() << "Point_1 of array2: " << pointArray2.Element(1).GetX() << "," << pointArray2.Element(1).GetY();
pointArray1.Element(0).Move(25,30); // 通过指针访问数组元素的成员
pointArray1.Element(1).Move(35,40); // 通过指针访问数组元素的成员
qDebug() << "After the moving of pointArray1: ";
qDebug() << "Point_0 of array2: " << pointArray2.Element(0).GetX() << "," << pointArray2.Element(0).GetY();
qDebug() << "Point_1 of array2: " << pointArray2.Element(1).GetX() << "," << pointArray2.Element(1).GetY();
return a.exec();
}
//运行结果:
//拷贝前后示意图:
从图中可以看出默认的拷贝构造函数将两个对象的对应数据项简单复制后,pointArray1 的成员 points 和 pointArray2 的成员 points 具有相同的值,也就是说两个指针指向同一个内存地址,表面上好像完成了复制,但是并没有形成真正的副本。因此当程序中移动 pointArray1 中的点时,也影响到了 pointArray2 。这种效果就是浅拷贝。
浅拷贝还有更大的弊病,在程序结束之前 pointArray1 和 pointArray2 的析构函数会被自动调用,动态分配的内存空间会被释放。由于两个对象共用了同一块内存空间,因此该空间被释放两次,于是导致运行时错误。解决办法是编写拷贝构造函数,实现“深拷贝”。
下面是对上述代码进行调整,加入拷贝构造函数之后,用于实现“深拷贝”的代码:
#include <QCoreApplication>
#include <QDebug>
class Point
{
public:
Point(){
X=Y=0;
qDebug() << "Default Constructor called.";
}
Point(int xx,int yy){
X=xx;
Y=yy;
qDebug() << "Constructor called.";
}
~Point(){
qDebug() << "Destructor called.";
}
int GetX() const {
return X;
}
int GetY() const {
return Y;
}
void Move(int x,int y){
X=x;
Y=y;
}
private:
int X,Y;
};
class ArrayOfPoints
{
public:
ArrayOfPoints(int n){
numberOfPoints = n;
points = new Point[n];
}
ArrayOfPoints(ArrayOfPoints& pointsArray); ///< 实现深拷贝
~ArrayOfPoints(){
qDebug() << "Deleting...";
numberOfPoints = 0;
delete [] points;
}
Point& Element(int n){
return points[n];
}
private:
Point *points;
int numberOfPoints;
};
ArrayOfPoints::ArrayOfPoints(ArrayOfPoints& pointsArray){ ///< 实现深拷贝
numberOfPoints = pointsArray.numberOfPoints;
points = new Point[numberOfPoints];
for (int i=0; i<numberOfPoints; i++) {
points[i].Move(pointsArray.Element(i).GetX(), pointsArray.Element(i).GetY());
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int number = 64;
ArrayOfPoints pointArray1(number); // 创建对象数组
pointArray1.Element(0).Move(5,10); // 通过指针访问数组元素的成员
pointArray1.Element(1).Move(15,20); // 通过指针访问数组元素的成员
ArrayOfPoints pointArray2(pointArray1); // 创建对象数组副本
qDebug() << "Copy of pointsArray1: ";
qDebug() << "Point_0 of array2: " << pointArray2.Element(0).GetX() << "," << pointArray2.Element(0).GetY();
qDebug() << "Point_1 of array2: " << pointArray2.Element(1).GetX() << "," << pointArray2.Element(1).GetY();
pointArray1.Element(0).Move(25,30); // 通过指针访问数组元素的成员
pointArray1.Element(1).Move(35,40); // 通过指针访问数组元素的成员
qDebug() << "After the moving of pointArray1: ";
qDebug() << "Point_0 of array2: " << pointArray2.Element(0).GetX() << "," << pointArray2.Element(0).GetY();
qDebug() << "Point_1 of array2: " << pointArray2.Element(1).GetX() << "," << pointArray2.Element(1).GetY();
return a.exec();
}
//运行结果: