4-7 复制一个员工:赋值构造函数
本节编程练习不计算学习进度,请电脑登录imooc.com操作

复制一个员工:赋值构造函数

上一小节中,我们介绍了构造函数和析构函数。这一小节,我们来介绍一个特殊的构造函数。

先来看一个例程:

int main(int argc,char **argv)
{
    Staff staffA;
    Staff staffB = staffA;

    return 0;
}

我们先实例化了一个对象 staffA,然后又实例化了一个对象 staffB。希望 staffB 和 staffA 具有相同的内容,或者说希望 staffB 是 staffA 的副本,那么我们一般直接在实例化的时候进行赋值就可以了。

Staff staffB = staffA;

这样做了之后,C++ 会自动为我们拷贝 staffA 中的成员变量到 staffB 的成员变量中,但是这种自动拷贝机制在某些情况下无法完成我们想要的动作,甚至有可能会出错。我们来具体看一下。

在 Staff 类中添加一些内容:

Staff.hpp

#include <string>

class Staff
{
public:
    Staff(std::string _name, int _age);
    ~Staff();

public:
    std::string name;
    int age;

    char * mem = nullptr;
};

Staff.cpp

#include "Staff.hpp"
#include <stdio.h>

Staff::Staff(std::string _name, int _age)
{
    mem = (char *)malloc(20);
    name = _name;
    age = _age;
    printf("构造函数被调用\n");
}

Staff::~Staff()
{
    if(mem != nullptr){
        free(mem);
        mem = nullptr;
    }
    printf("析构函数被调用\n");
}

在上面的代码中,在类中定义了一个指针,在构造函数中,通过 malloc 函数分配了一个 20 字节大小的堆内存,然后将这片堆内存的首地址赋值给了这个指针。在析构函数中,我们将这片堆内存释放掉。

这个时候,我们再进行一开始的操作:

Staff staffB = staffA;

先来看看 staffA 在实例化之后的内存布局:

mem 指针指向了一片 20 个字节大小的堆内存。

这个时候,再来看看执行了Staff staffB = staffA;之后,staffB 的内存布局会怎么样:

可以看到,在 C++ 默认的复制模式之下,两个对象中的 mem 指针指向了同一片内存。因为 C++ 默认的复制模式只会简单得把成员的值进行复制,面对这个 mem 指针,他只会把指针的值进行拷贝,最后的结果就是 mem 指针指向了同一片内存。

这种拷贝方式,被称之为浅拷贝。

赋值构造函数

Staff staffB = staffA;

当我们使用这种方式实例化对象的时候,并不会调用普通构造函数,而是会调用一个特殊的构造函数,被称之为赋值构造函数或者拷贝构造函数。如果我们没有写,那么就会按照浅拷贝的方式来进行复制。一个拷贝构造函数看起来就像下面这样:

Staff(const Staff & staff);

这个函数中只有一个参数 staff,表示要拷贝的对象,在我们的例子中,就是 staffA。(const 和 & 我们在后续的课程中会具体讲解)

那么我们来完整的编写一下这个函数

Staff.hpp

#include <string>

class Staff
{
public:
    Staff(std::string _name, int _age);
    Staff(const Staff & staff);
    ~Staff();

public:
    std::string name;
    int age;

    char * mem = nullptr;
};

Staff.cpp

#include "Staff.hpp"
#include <stdio.h>

Staff::Staff(std::string _name, int _age)
{
    mem = (char *)malloc(20);
    name = _name;
    age = _age;
    printf("构造函数被调用\n");
}

Staff::Staff(const Staff & staff)
{
    name = staff.name;
    age = staff.age;

    mem = (char *)malloc(20);
    memcpy(mem, staff.mem, 20);
}

Staff::~Staff()
{
    if(mem != nullptr){
        free(mem);
        mem = nullptr;
    }
    printf("析构函数被调用\n");
}

任务

  1.  
下一节