C++拷贝构造函数

拷贝构造函数

每个类都有多个构造函数和一个析构函数。此外,类还可以有一个拷贝构造函数(copy constructor)。

拷贝构造函数用于拷贝对象。也就是说,这个构造函数的参数是这个类的对象,执行这个构造函数之后,会产生一个与原来对象一样的对象(实际上是用原来对象的数据初始化了一个对象)。

构造函数的签名如下:

ClassName (const ClassName&)

下面给出一个栗子:

Circle.h

class Circle {
public:
    //无参构造函数
    Circle();
    //有参构造函数
    Circle(double);
    //析构函数
    ~Circle();
    //获取圆的面积
    double getArea();
    //获取圆的半径
    double getRadius();

private:
    //圆的半径
    double radius;
    //定义常量圆周率
    const double PI = 3.14159;
    //对象个数
    static int objectNumber;
};

Circle.cpp

#include "Circle.h"
#include <iostream>

using namespace std;

int Circle::objectNumber = 0;

//无参构造函数
Circle::Circle() {
    this->radius = 1;
    objectNumber++;
    cout << "当前对象的个数是" << objectNumber << endl;
}

//有参构造函数
Circle::Circle(double radius) {
    this->radius = radius;
    objectNumber++;
    cout << "当前对象的个数是" << objectNumber << endl;
}

//析构函数
Circle::~Circle(){
    objectNumber--;
    cout << "当前对象的个数是" << objectNumber << endl;
}

//获取面积
double Circle::getArea() {
    return radius*radius*PI;
}

//获取半径
double Circle::getRadius(){
    return this->radius;
}

main.cpp

#include <iostream>
#include "Circle.h"

using namespace std;

int main()
{
    //调用无参构造函数
    cout << "创建对象p1" << endl;
    Circle* p1 = new Circle(2);

    //调用拷贝构造函数
    cout << "创建对象p2" << endl;
    Circle* p2 = new Circle(*p1);

    //调用有参构造函数,参数为3
    cout << "创建对象p3" << endl;
    Circle* p3 = new Circle(3);

    cout << "-------------------------------"<< endl;

    cout << "p1半径为" << p1->getRadius() << endl;
    cout << "p2半径为" << p2->getRadius() << endl;
    cout << "p3半径为" << p3->getRadius() << endl;

    cout << "-------------------------------"<< endl;
    //销毁p1
    cout << "销毁对象p1" << endl;
    delete p1;

    //销毁p2
    cout << "销毁对象p2" << endl;
    delete p2;

    //销毁p3
    cout << "销毁对象p3" << endl;
    delete p3;


    return 0;
}

运行结果:

由于我们调用的是缺省的拷贝构造函数,所以创建p2时,对象的个数没有加1。

还有一个问题是,我们调用的拷贝构造函数,是将p1的地址给了p2,还是新开辟了内存?

更改一下main.cpp

#include <iostream>
#include "Circle.h"

using namespace std;

int main()
{
    //调用无参构造函数
    cout << "创建对象p1" << endl;
    Circle p1(2);

    //调用拷贝构造函数
    cout << "创建对象p2" << endl;
    Circle p2(p1);

    //调用有参构造函数,参数为3
    cout << "创建对象p3" << endl;
    Circle p3(3);

    cout << "-------------------------------"<< endl;

    cout << "p1半径为" << p1.getRadius() << endl;
    cout << "p1地址为" << &p1 << endl;
    //销毁p1
    cout << "销毁对象p1" << endl;
    delete &p1;
     cout << "-------------------------------"<< endl;
    cout << "p2半径为" << p2.getRadius() << endl;
    cout << "p2地址为" << &p2 << endl;
    //销毁p2
    cout << "销毁对象p2" << endl;
    delete &p2;
     cout << "-------------------------------"<< endl;
    cout << "p3半径为" << p3.getRadius() << endl;
    //销毁p3
    cout << "销毁对象p3" << endl;
    delete &p3;

    return 0;
}

运行结果:

 

可以看到,p1和p2有着两个不同的地址,而且p1被delete之后,p2的值还在。所以,拷贝构造函数会新开辟内存空间。

自定义拷贝构造函数

接下来解决之前对象个数不一致的问题。为了能让我们的对象个数在拷贝构造时也变化,我们就要自定义一个拷贝构造函数。

首先在Circle.h的public下添加:

//拷贝构造函数
Circle (const Circle&);

然后在Circle.cpp中添加函数体:

//拷贝构造函数
Circle::Circle(const Circle& c) {
    this->radius = c.radius;
    objectNumber++;
    cout << "拷贝成功" << endl;
    cout << "当前对象的个数是" << objectNumber << endl;
}

然后再次运行main.cpp(main.cpp不变)

OK,现在就符合实际情况了。

深拷贝和浅拷贝

之前我们说到的都是浅拷贝。也就是说,如果类中有一个指针变量,在拷贝时,指针变量的值不会改变。这时,两个虽然两个对象具有不同的地址,但是两个对象的指针却指向同一个地址。当一个对象被销毁时,它的指针指向的内存也会销毁。因此,另一个对象销毁时,就会产生错误。

由此引出深拷贝。即让指针不指向同一个地址,这时就一定要自定义拷贝构造函数,给新对象的指针分配内存了。

 (顺便一提,浅拷贝构造函数相当于用=,也就是说Circle p2(p1)也可以写为Circle p2 = p1)

假设我的类中有一个指针p,下面是浅拷贝构造函数:

//浅拷贝构造函数
Circle::Circle(const Circle& c) {
    this->radius = c.radius;
    this->p = c.p;
    objectNumber++;
    cout << "拷贝成功" << endl;
    cout << "当前对象的个数是" << objectNumber << endl;
}

此时,没有为新对象的指针分配内存

main.cpp如下:

#include <iostream>
#include "Circle.h"

using namespace std;

int main()
{
    //调用无参构造函数
    cout << "创建对象p1" << endl;
    Circle p1(2);

    //调用有参构造函数,参数为1
    cout << "创建对象p2" << endl;
    Circle p2(p1);


    cout << "-------------------------------"<< endl;


    cout << "p1的指针p的值为" << p1.p << endl;

     cout << "-------------------------------"<< endl;

    cout << "p2的指针p的值为" << p2.p << endl;


    return 0;
}

运行结果:

可以看到,两个指针的值都是0x82a978

再看深拷贝的拷贝构造函数:

//深拷贝构造函数
Circle::Circle(const Circle& c) {
    this->radius = c.radius;
    //先开辟内存
    this->p = new int;
    //再赋值
    *p = *(c.p);
    objectNumber++;
    cout << "拷贝成功" << endl;
    cout << "当前对象的个数是" << objectNumber << endl;
}

main.cpp同上

运行结果:

 此时两个指针指向的就是不同的地址了。

posted @ 2020-04-22 14:01  川尘  阅读(400)  评论(0编辑  收藏  举报
`