25. 深浅拷贝

一、深浅拷贝问题

  在 C++ 中,对象的拷贝可以分为浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。

  浅拷贝 是指当一个对象拷贝另一个对象时,只是简单地复制了对象的各个成员变量的值,包括指向其他对象的指针。这意味着,如果源对象和目标对象中的成员变量是指针类型,那么浅拷贝只会复制指针的值,而不是指针指向的数据。因此,源对象和目标对象将共享相同的指针指向的数据,这可能会导致潜在的问题,比如当一个对象被销毁时,它可能会释放资源,导致另一个对象中的指针悬空,又比如两个对象将共享同一块内存,如果一个对象改变了那块内存的内容,另一个对象也会受到影响。默认情况下,编译器会为类生成浅拷贝构造函数和浅拷贝赋值运算符。

  深拷贝 是指当一个对象拷贝另一个对象时,不仅复制了对象的各个成员变量的值,而且还复制了这些成员变量所指向的数据。这意味着,如果源对象和目标对象中的成员变量是指针类型,那么深拷贝会分配新的内存,为指针指向的数据创建一个新的副本,并将指针指向这个新副本。因此,源对象和目标对象将拥有独立的资源,新旧对象之间不会共享任何非静态成员,互不影响。

  在 C++ 中,默认的拷贝构造函数和拷贝赋值运算符通常执行浅拷贝。如果你需要实现深拷贝,你需要在你的类中自定义拷贝构造函数和拷贝赋值运算符,以确保正确地复制所有成员变量所指向的数据。

二、什么是浅拷贝

  浅拷贝 只是简单地复制对象的所有成员变量,包括指针。如果对象的成员变量中有动态分配的内存(如指针指向的内存),则浅拷贝只是复制了指针本身,而不是它所指向的内存。这意味着两个对象现在指向同一块内存区域。

浅拷贝

class School
{
private:
    string name;
    string address;

public:
    School(void);
    School(string name, string address);

    void showInfo(void);

    string getName(void);
    void setName(string name);

    string getAddress(void);
    void setAddress(string address);
};

School::School(void) : name(""), address("") {}

School::School(string name, string address) : name(name), address(address) {}

void School::showInfo(void)
{
    cout << "School{name: " << name << ", address: " << address << "}" << endl;
}

string School::getName(void)
{
    return name;
}

void School::setName(string name)
{
    this->name = name;
}

string School::getAddress(void)
{
    return address;
}

void School::setAddress(string address)
{
    this->address = address;
}
class Student
{
private:
    string name;
    int age;
    School *school;

public:
    Student(void);
    Student(string name, int age);

    void showInfo(void);

    string getName(void);
    void setName(string name);

    int getAge(void);
    void setAge(int age);

    School * getSchool(void);
    void setSchool(School *school);
};

Student::Student(void) : name(""), age(0), school(new School()) {}
Student::Student(string name, int age) : name(name), age(age) {}

void Student::showInfo(void)
{
    cout << "Studet{name: " << name << ", age: " << age << ", school: " << school->getName() << "}" << endl;
}

string Student::getName(void)
{
    return name;
}

void Student::setName(string name)
{
    this->name = name;
}

int Student::getAge(void)
{
    return age;
}

void Student::setAge(int age)
{
    this->age = age;
}

School * Student::getSchool(void)
{
    return school;
}

void Student::setSchool(School *school)
{
    this->school = school;
}
#include <iostream>

using namespace std;

int main(void)
{
    School *school = new School("友枝小学", "京都府京都中京区");

    Student s1("木之本樱", 10);
    s1.setSchool(school);
    s1.showInfo();

    Student s2(s1);
    s2.setAge(12);
    s2.getSchool()->setName("友枝中学");
    s2.showInfo();

    s1.showInfo();

    delete school;

    return 0;
}

三、什么是深拷贝

  深拷贝不仅会复制对象的所有成员变量,还会为指针所指向的内存分配新的内存,并将内容复制到新的内存区域。这样,两个对象就有各自独立的内存区域。如果我们想要实现深拷贝,需要自己重写类的拷贝构造函数。

深拷贝

  在 Student 类中重写拷贝构造函数和析构函数。

class Student
{
private:
    string name;
    int age;
    School *school;

public:
    Student(void);
    Student(string name, int age);
    Student(const Student &student);
    ~Student(void);

    void showInfo(void);

    string getName(void);
    void setName(string name);

    int getAge(void);
    void setAge(int age);

    School * getSchool(void);
    void setSchool(School *school);
};

Student::Student(void) : name(""), age(0), school(new School()) {}
Student::Student(string name, int age) : name(name), age(age) , school(new School()) {}

Student::Student(const Student &student) : name(student.name), age(student.age)
{
    school = new School(student.school->getName(), student.school->getAddress());
}

Student::~Student(void)
{
    if (school != nullptr)
    {
        delete school;
    }
}

void Student::showInfo(void)
{
    cout << "Studet{name: " << name << ", age: " << age << ", school: " << school->getName() << "}" << endl;
}

string Student::getName(void)
{
    return name;
}

void Student::setName(string name)
{
    this->name = name;
}

int Student::getAge(void)
{
    return age;
}

void Student::setAge(int age)
{
    this->age = age;
}

School * Student::getSchool(void)
{
    return school;
}

void Student::setSchool(School *school)
{
    this->school = school;
}

  修改 main() 函数:

int main(void)
{
    School *school = new School("友枝小学", "京都府京都中京区");

    Student s1("木之本樱", 10);
    s1.setSchool(school);
    s1.showInfo();

    Student s2(s1);
    s2.setAge(12);
    s2.getSchool()->setName("友枝中学");
    s2.showInfo();

    s1.showInfo();

    return 0;
}
posted @ 2023-05-16 21:51  星光映梦  阅读(20)  评论(0编辑  收藏  举报