C++超详细讲解拷贝构造函数

C++超详细讲解拷贝构造函数

什么是拷贝构造函数

C++中的拷贝构造函数是一种特殊的构造函数,用于关于同类对象进行复制初始化。当使用一个对象去初始化另一个同类对象时,就会调用拷贝构造函数。拷贝构造函数通常使用一个类的引用作为其参数,并且不允许传入除该引用以外的任何值。

拷贝构造函数的使用场景

  1. 传递类对象给函数时,会调用拷贝构造函数;
  2. 返回类对象时,会调用拷贝构造函数;
  3. 在类中对当前类对象生成一个副本时,会调用拷贝构造函数。

拷贝构造函数示例1:深拷贝

在以下示例中,我们定义了一个学生类,并定义了两个对象stu1和stu2。在stu1作为参数传递给函数print()时,会调用一次拷贝构造函数。由于没有定义自己的拷贝构造函数,所以系统自动提供了一个默认的拷贝构造函数——进行逐个赋值;在函数print()中,我们输出了相应的学生信息。在运行过程中,我们可以看到两个对象的信息都被成功地输出。

#include <iostream>
#include <string>

using namespace std;

class Student
{
public:
    Student(string name, int age, int* scores);
    Student(const Student& stu);    // 拷贝构造函数
    void print();
    ~Student();
private:
    string name;
    int age;
    int* scores;
};

Student::Student(string name, int age, int* scores)
{
    this->name = name;
    this->age = age;
    this->scores = new int[3];
    for (int i = 0; i < 3; i++)
    {
        this->scores[i] = scores[i];
    }
}

Student::Student(const Student& stu)    // 拷贝构造函数
{
    this->name = stu.name;
    this->age = stu.age;
    this->scores = new int[3];
    for (int i = 0; i < 3; i++)
    {
        this->scores[i] = stu.scores[i];
    }
}

void Student::print()
{
    cout << "Name: " << this->name << endl;
    cout << "Age: " << this->age << endl;
    cout << "Scores: ";
    for (int i = 0; i < 3; i++)
    {
        cout << this->scores[i] << " ";
    }
    cout << endl;
}

Student::~Student()
{
    if (this->scores)
    {
        delete[] this->scores;
    }
} 

void print(Student stu)
{
    cout << "Print a Student object: " << endl;
    stu.print();
}

int main()
{
    int scores[3] = {90, 80, 70};
    Student stu1("Tom", 18, scores);
    Student stu2 = stu1;    // 调用一次拷贝构造函数
    stu2.print();
    print(stu1);    // 调用一次拷贝构造函数
    return 0;
}

拷贝构造函数示例2:浅拷贝

在以下示例中,我们定义了一个沙漏类,并定义了两个对象Hourglass1和Hourglass2,其中Hourglass1的high属性指向一个动态分配的int型变量,并在析构函数中释放空间,而Hourglass2则是Hourglass1的复制。由于没有自定义的拷贝构造函数来完成深拷贝,因此默认的拷贝构造函数将进行浅拷贝,即直接将指针复制过去,导致两个对象共享同一块内存空间。在释放Hourglass2时,由于析构函数会先释放这块空间,而当再次释放Hourglass1时,程序因为重复释放内存空间而抛出异常。

#include<iostream> 
#include<cstring> 

using namespace std;

class Hourglass
{
public:
    Hourglass(int myHigh = 10); 
    Hourglass(const Hourglass& hg); // 拷贝构造函数
    ~Hourglass(); 
    void PrintHourGlassHeight(); 
private:
    int high; 
    int* low; 
};

Hourglass::Hourglass(int myHigh) 
{ 
    high = myHigh; 
    low = new int[high]; 
    memset(low, 0, sizeof(int) * high); 
} 

Hourglass::~Hourglass()
{
    delete[] low;
    cout << "Release Hourglass memory successfully!" << endl;
}

Hourglass::Hourglass(const Hourglass& hg) // 拷贝构造函数
{
    high = hg.high;
    low = hg.low;
}

void Hourglass::PrintHourGlassHeight()
{
    cout << "The high of the Hourglass: " << high << endl;
}

int main()
{
    Hourglass Hourglass1;
    Hourglass Hourglass2(Hourglass1);    // 调用一次拷贝构造函数
    Hourglass2.PrintHourGlassHeight();
    return 0;
}

总结

C++中的拷贝构造函数是一种特殊的构造函数,用于关于同类对象进行复制初始化。适当地使用拷贝构造函数可以避免问题出现,但若不谨慎使用则可能会造成内存空间重复释放的问题。在使用时,需要考虑数据的类型、数据的大小等多方面的因素,针对性地选择不同的拷贝构造函数实现方式。

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

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

相关文章

  • 易语言柱状图控件、组件的使用方法

    易语言柱状图控件、组件的使用方法 什么是柱状图控件/组件 在易语言中,柱状图控件/组件是一种用于在应用程序中创建二维列状图形的控件/组件。它允许您用简单的方式表示大量数据中的任何一个变化。柱状图控件/组件可以无限制地添加数据和数据系列,并可以为每个系列和每个数据点提供样式和标签。 创建柱状图控件/组件 在易语言编辑器中,打开需要添加柱状图控件/组件的窗口或对…

    other 2023年6月27日
    00
  • mybatis中的转义符

    以下是关于MyBatis中的转义符的完整攻略,包括定义、使用方法、示例说明和注意事项。 定义 在MyBatis中,有些特殊字符需要使用转义符转义,以避免解析错误。例如,如果SQL语句中包含单引号,需要使用转义符将其转义为两个单引号,否则会导致SQL语句解析错误。 使用方法 在MyBatis中,使用转义符的方法如下: 单引号转义 在SQL语句中如果需要使用单引…

    other 2023年5月8日
    00
  • AirPods Pro一直断连怎么办 AirPods Pro连接不稳定的解决办法

    AirPods Pro一直断连怎么办 如果你的 AirPods Pro 经常断连,可以尝试以下解决方法。 1. 确认设备连接状态 首先,请确保你的设备(如 iPhone、iPad 或 Mac)已经完成了与 AirPods Pro 的连接过程。然后,打开设置中的蓝牙,确认 AirPods Pro 已经成功连接。如果连接不成功,请尝试将 AirPods Pro …

    other 2023年6月27日
    00
  • dos变量定义和引用方法

    DOS变量定义和引用方法是在DOS命令行窗口中定义和使用变量的一种方式。下面是详细的攻略: 定义DOS变量 在DOS中,可以通过set命令来定义变量。例如,要定义一个名为myVar的变量,其值为hello world,可以使用以下命令: set myVar=hello world 在此示例中,将创建一个名为myVar的变量,并将其值设置为hello worl…

    other 2023年6月27日
    00
  • Android context源码详解及深入分析

    Android Context源码详解及深入分析攻略 1. 什么是Android Context? 在Android开发中,Context是一个非常重要的概念。它代表了当前应用程序的运行环境,提供了访问应用程序资源和系统服务的接口。Context是一个抽象类,它的具体实现类是ContextImpl。 2. Context的主要功能 Context提供了许多重…

    other 2023年8月21日
    00
  • Android端使用Modbus协议的简单方法

    Android端使用Modbus协议的简单方法 什么是Modbus协议? Modbus是一种串行通信协议,常用于连接控制器和远程终端单元(RTU)设备。它具有开放、简单且易于使用的特点,因此可用于通信的许多领域,包括工业自动化领域。Modbus协议现已发展成为一种标准工业协议,常见于各种类型的PLC和SCADA系统以及其他控制设备上。 在Android端使用…

    other 2023年6月27日
    00
  • 详解WPF中用户控件和自定义控件的使用

    详解WPF中用户控件和自定义控件的使用 WPF中的控件可以根据我们的需要进行自定义,这就涉及到两种方式:用户控件和自定义控件。本文将详细讲解这两种方式的使用方法。 用户控件 用户控件是由多个控件组成的可重用控件。我们可以将多种原生控件组合在一起,用 C# 或 VB.NET 编写代码,从而构建出一个新的用户控件。在开发过程中,用户控件可以像其他控件那样使用、放…

    other 2023年6月25日
    00
  • Win10右键菜单怎么添加Windows Defender扫描项目?

    添加Windows Defender扫描项目到Win10右键菜单的具体步骤如下: 打开注册表编辑器。按下Win+R打开运行窗口,输入“regedit”,按下回车键即可打开注册表编辑器。 找到以下路径:HKEY_CLASSES_ROOT\Directory\Background\shell 右键shell,选择新建项(New>Key),输入“Window…

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