浅拷贝 静态数组的空间体现深拷贝的效果

#include <iostream>
#include <string>

using namespace std;
#define SEX_SIZE 10

class Student
{
public:
    Student(string name)
    {
        Age = 10;
        Name = new string(name);
        strcpy(Sex, "男");
    }
    ~Student()
    {
        delete Name;
    }

    void ShowInfo()
    {
        cout << "年龄:" << Age << endl;
        cout << "姓名:" << *Name << endl;
        cout << "性别:" << Sex << endl;
        cout << endl;
    }
    string* GetName()
    {
        return  Name;
    }

    string** GetNamePtr()
    {
        return &Name;
    }

    void ChangeSex(const char* sexNew, size_t size)
    {
        memcpy(Sex, sexNew, size);
    }
private:
    int Age;
    string* Name;
    char Sex[SEX_SIZE];
};


int main()
{
    Student stu("小明");
    cout << "stu:" << endl;
    stu.ShowInfo();
    cout << "----------------------" << endl;

    Student stu_(stu);
    Student* stu2 = &stu_;
    char sexNew[SEX_SIZE] = "女";
    stu2->ChangeSex(sexNew, sizeof(sexNew));

    cout << "stu2:" << endl;
    stu2->ShowInfo();
    cout << "stu:" << endl;
    stu.ShowInfo();
    cout << "----------------------" << endl;

    string nameNew("悟空");
    *stu.GetName() = nameNew;
    cout << "stu2:" << endl;
    stu2->ShowInfo();
    cout << "stu:" << endl;
    stu.ShowInfo();
    cout << "----------------------" << endl;

    // 浅拷贝,会出现 Name 两次释放的情况
    // 这里将一个置为 null
    *stu2->GetNamePtr() = nullptr;

    return 0;
}

上面进行了一次浅拷贝测试, 注意浅拷贝,同一块内存释放两次的问题。

输出:

性别:男

----------------------
stu2:
年龄:10
姓名:小明
性别:女

stu:
年龄:10
姓名:小明
性别:男

----------------------
stu2:
年龄:10
姓名:悟空
性别:女

stu:
年龄:10
姓名:悟空
性别:男

----------------------

浅拷贝,从输出可见,静态数组只有一个对象受到影响,从->。指针对象,两个都受到了影响:从小明->悟空

深拷贝

增加一个拷贝构造函数:

Student(const Student& obj)
    {
        Age = obj.Age;
        memcpy(Sex, obj.Sex, SEX_SIZE);
        Name = new string(*obj.Name);
    }

主函数中修改一下, 深拷贝不再释放两次:

// 浅拷贝,会出现 Name 两次释放的情况
// 这里将一个置为 null
//*stu2->GetNamePtr() = nullptr;

输出:

stu:
年龄:10
姓名:小明
性别:男

----------------------
stu2:
年龄:10
姓名:小明
性别:女

stu:
年龄:10
姓名:小明
性别:男

----------------------
stu2:
年龄:10
姓名:小明
性别:女

stu:
年龄:10
姓名:悟空
性别:男

----------------------

重载 = 运算符

Student& operator=(const Student& obj)
{
    if (this == &obj) // 防止自我赋值
    {
        return *this;
    }

    Age = obj.Age;
    memcpy(Sex, obj.Sex, SEX_SIZE);
    delete Name; // 删除旧的
    Name = new string(*obj.Name);
    return *this;
}

拷贝构造函数一般这些情况下调用:

  1. 对象初始化
  2. 函数参数传递(值传递)
  3. 函数返回值(非引用类型)
  4. 容器类操作 // 添加对象时

// 引用传值不会调用拷贝构造函数
// 了解下新特性 移动构造函数

注意这个与拷贝构造函数的区别:

Student stu("小明");

Student stu_ = stu; // 这个 = 号是对象初始化,调用的拷贝构造函数
Student stu3("牛魔王");
stu3 = stu  // 这个 = 号是赋值,调用的是 operator= 重载运算符

注意上面两个 = 的区别。