c++详细讲解构造函数的拷贝流程

c++详细讲解构造函数的拷贝流程

什么是构造函数

在C++中,构造函数是一种特殊的成员函数,用于创建和初始化对象。当一个对象被创建时,构造函数会自动调用,完成对象的初始化工作。

构造函数的拷贝流程

当需要创建一个新对象并将其初始化为另一个对象的副本时,就需要使用到拷贝构造函数。拷贝构造函数用于实现一个对象复制另一个对象的所有成员变量的功能。

在C++中,每个类都有一个默认的拷贝构造函数,它会按照成员变量的顺序逐个复制。以下是一个简单的示例:

class Person {
public:
    int age;
    std::string name;
};

int main() {
    Person p1;
    p1.age = 20;
    p1.name = "Tom";

    Person p2 = p1; // 使用拷贝构造函数将p1复制给p2

    std::cout << "p1's age is " << p1.age << ", name is " << p1.name << std::endl;
    std::cout << "p2's age is " << p2.age << ", name is " << p2.name << std::endl;

    return 0;
}

输出结果为:

p1's age is 20, name is Tom
p2's age is 20, name is Tom

可以看到,p1和p2的成员变量都被正确地复制过来了。拷贝构造函数会在创建新对象时调用,并将原对象的值拷贝到新对象上。

浅拷贝

以上示例中的拷贝构造函数实现的是浅拷贝。浅拷贝只是将原对象的成员变量的值复制过来,并没有创建新的对象,也没有为成员变量分配新的内存空间。这种方式的缺点是,如果原对象和副本对象指向同一块内存时,会导致副本对象发生意外修改,原对象的值也会被改变。

以下是一个示例:

class Person {
public:
    int age;
    std::string* name;
    Person(int age, std::string* name) {
        this->age = age;
        this->name = name;
    }
};

int main() {
    std::string name = "Tom";
    Person p1(20, &name);
    Person p2 = p1; // 使用拷贝构造函数将p1复制给p2

    std::cout << "p1's name is " << *(p1.name) << std::endl;
    std::cout << "p2's name is " << *(p2.name) << std::endl;

    *(p2.name) = "Jerry"; // 修改p2的name

    std::cout << "After modification:" << std::endl;
    std::cout << "p1's name is " << *(p1.name) << std::endl;
    std::cout << "p2's name is " << *(p2.name) << std::endl;

    return 0;
}

输出结果为:

p1's name is Tom
p2's name is Tom
After modification:
p1's name is Jerry
p2's name is Jerry

可以看到,修改了p2的成员变量name,同时也修改了p1的成员变量name。这是因为p1和p2的成员变量name指向同一块内存空间,造成了意外修改。

深拷贝

为了规避上述的问题,需要使用到深拷贝。深拷贝会为新对象重新分配内存空间,并将原对象的值复制到新的内存空间中,从而避免了意外修改。

以下是一个示例:

class Person {
public:
    int age;
    std::string* name;
    Person(int age, std::string* name) {
        this->age = age;
        this->name = new std::string(*name); // 新分配内存空间,拷贝name指向的字符串
    }
    ~Person() {
        delete name; // 在析构函数中释放内存空间
    }
    Person(const Person& p) { // 拷贝构造函数
        this->age = p.age;
        this->name = new std::string(*(p.name)); // 深拷贝
    }
};

int main() {
    std::string name = "Tom";
    Person p1(20, &name);
    Person p2 = p1; // 使用拷贝构造函数将p1复制给p2

    std::cout << "p1's name is " << *(p1.name) << std::endl;
    std::cout << "p2's name is " << *(p2.name) << std::endl;

    *(p2.name) = "Jerry"; // 修改p2的name

    std::cout << "After modification:" << std::endl;
    std::cout << "p1's name is " << *(p1.name) << std::endl;
    std::cout << "p2's name is " << *(p2.name) << std::endl;

    return 0;
}

输出结果为:

p1's name is Tom
p2's name is Tom
After modification:
p1's name is Tom
p2's name is Jerry

可以看到,修改了p2的成员变量name后,p1的成员变量name并没有发生改变。这是因为p1和p2的成员变量name指向不同的内存空间,使用深拷贝避免了意外修改。同时,在析构函数中释放了拷贝出来的内存空间。

结论

构造函数、拷贝构造函数是自定义类中必须要定义的两个函数。拷贝构造函数会在创建新对象时调用,并将原对象的值拷贝到新对象上,在使用时需要注意浅拷贝和深拷贝的区别。如果对象中存在指针类型成员变量,则必须使用深拷贝避免数据异常。

阅读剩余 67%

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c++详细讲解构造函数的拷贝流程 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • python和ipython有什么区别?

    下面是关于“python和ipython有什么区别?”的完整攻略: 1. Python 和 IPython Python 是一种高级编程语言,它具有简易学读性强、可移植性好等特点,被广泛应用于各种领域。IPython 是 Python 的一个增强版本,它供更多的交互式功能和工具,使得 Python程更加方便和高效。 2. Python 和 IPython 的…

    other 2023年5月7日
    00
  • Python pip安装第三方库的攻略分享

    Python pip安装第三方库的攻略分享 Python的pip工具是一个强大的包管理器,用于安装和管理第三方库。下面是安装第三方库的详细攻略。 步骤一:安装pip 如果你的Python版本是3.4或更高版本,pip已经默认安装在你的系统中。你可以通过在命令行中输入以下命令来检查pip是否已安装: pip –version 如果pip已经安装,你将看到pi…

    other 2023年8月6日
    00
  • javascript的indexOf忽略大小写的方法

    JavaScript的indexOf忽略大小写的方法攻略 在JavaScript中,indexOf方法用于查找字符串中某个子字符串的位置。默认情况下,indexOf方法是区分大小写的,但是我们可以通过一些技巧来实现忽略大小写的搜索。下面是一种常用的方法: 将字符串转换为小写或大写形式。 使用转换后的字符串进行搜索。 下面是一个示例说明: // 示例1:忽略大…

    other 2023年8月18日
    00
  • React classnames原理及测试用例

    React classnames原理及测试用例 1. 原理说明 在React中,classnames是一个常用的工具库,用于动态生成类名。它可以帮助我们更方便地处理条件性的类名拼接,让代码更简洁易读。 工作原理:classnames库提供了一个classnames函数,可以接受多个参数,参数可以是字符串、对象和数组。它会根据参数的类型进行判断,根据不同的情况…

    other 2023年6月28日
    00
  • 在Linux系统上加密文件和目录的教程

    Linux系统上加密文件和目录的教程 1. 安装加密软件 Linux系统上有很多加密软件可供选择,请根据需要选择相应的软件进行安装。本文以GnuPG为例,介绍其基本使用方法。安装命令如下: sudo apt-get install gnupg 2. 生产GPG密钥对 GPG加密软件采用了公钥加密和私钥解密的方式进行文件加密,因此,需要先生产密钥对。执行以下命…

    other 2023年6月27日
    00
  • 深入理解Vue生命周期、手动挂载及挂载子组件

    深入理解Vue生命周期 Vue生命周期是Vue组件从创建到销毁直接的各个阶段,每个阶段都拥有自己的方法和属性。理解Vue生命周期非常重要,可以方便我们在合适的阶段做出更好的操作。 Vue生命周期分为8个阶段: beforeCreate:实例刚刚被创建,数据观测(data observer)和事件机制(event mechanism)未初始化。所以组件内一般无…

    other 2023年6月27日
    00
  • Java基础之static的用法

    Java基础之static的用法 1. static关键字的概述 在Java中,static是一个关键字,它可以用来修饰类的成员。当成员被static修饰时,它就变成了该类的静态成员,也即类级别的成员。静态成员不属于类的任何实例对象,而是与类本身相关联。在使用静态成员时,不需要通过实例对象来访问,可以通过类名直接调用。 2. static修饰变量的用法 2.…

    other 2023年6月28日
    00
  • securecrt字体变色多彩

    以下是SecureCRT字体变色多彩的完整攻略,包括两个示例说明。 1. SecureCRT字体变色多彩的方法 SecureCRT是一款常用的终端仿真软件,可以通过修改字体颜色来实现多彩的效果。具体方法如下: 打开SecureCRT软件,进入“Options”菜单,选择“Session Options”。 在“Session Options”窗口中,选择“A…

    other 2023年5月9日
    00
合作推广
合作推广
分享本页
返回顶部