【C++】详解拷贝构造

简介: 【C++】详解拷贝构造

拷贝构造的功能

拷贝构造函数可以把曾经实例化好的对象的数据拷贝给新创建的数据 ,可见说拷贝构造函数在功能上是构造函数的另一种形式。都是让对象初始化。

写法:

拷贝构造函数在语法层是构造函数的重载,函数名就是类名,无返回值,参数是该类类型对象的引用(为了保护被引用对象数据不被破坏,会在类型前面加上const)

Date(const Date& d) //以日期类为例,定义拷贝构造的写法
Date d1;
 Date d2(d1); //以日期类为例,实例化对象时的写法
 
Date d1;
 
Date d2 = d1;  //以日期类为例,实例化对象时的另一种写法

拷贝构造函数的参数为什么是引用类型

下面是定义的日期类的拷贝构造函数,但参数并不是引用类型

Date(const Date d)
{
  _year = d._year;
  _month = d._month;
  _day = d._day;
}

因为是传值,实例化对象时需要调用拷贝构造函数把数据拷贝过来,但拷贝数据函数的参数又需要掉用拷贝构造函数,如此就死循环了,拷贝构造函数会被无限调用。如图所示 这种情况编译器会强制报错

系统自动生成的拷贝构造函数

若未显式定义,编译器会生成默认的拷贝构造函数 默认的拷贝构造函数对象按内存存储 按字节序 完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝

下面代码中定义了一个时间类 Time ,又定义了一个日期类 Date , 时间类在日期类里实例化了对象_t,_t就是日期类的自定义类型,但并没有定义日期类的拷贝构造函数。那么系统自动生成的拷贝构造函数会怎么处理自定义类型_t和内置类型的年月日呢?

class Time {   //时间类
public:
 
Time() 
   {
_hour = 1;
_minute = 1;
_second = 1;
}
 
Time(const Time& t) //自定义时间类的拷贝构造函数
{
_hour = t._hour;
_minute = t._minute;
_second = t._second;
}
 
private:
 
int _hour;
int _minute;
int _second;
};
 
class Date  //日期类,但没有自定义拷贝构造函数
{
  
private:
// 基本类型(内置类型)
  int _year;
  int _month;
  int _day;
 
// 自定义类型
Time _t;  //时间类实例化对象 _t
  
};
 
int main(){
 
Date d1;
Date d2(d1); //拷贝对象d1的数据
 
 // 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
    // 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数
 
return 0;
}
 
 
 

只需明晰一点即可,系统自动生成的默认拷贝构造对内置类型进行浅拷贝对自定义类型,会调用自定义类型的拷贝构造函数,若自定义类型并未定义拷贝构造函数,系统便会自动生成。

下图是代码执行示意图

下图是逻辑示意图

拷贝构造的深拷贝与浅拷贝

概念

浅拷贝:

又称值拷贝,是按字节序拷贝的,通俗的讲别的数据长啥样就拷贝啥样。

浅拷贝的细节:下面代码中还是定义了一个日期类,但增加了一个int*的变量它指向一块空间。这是让默认构造函数进行浅拷贝会发生什么呢?

class Date //日期类,并没有定义拷贝构造函数
{
public:
 
  Date()//构造函数
  {
    _year = 1;
    _month = 1;
    _day = 1;
      _a = (int*)malloc(sizeof(int) * 7); //开辟空间并把空间的值初始化
      for (int i = 0; i < 7; i++)
      {
        _a[i] = 0;
      }
  }
 
private:
  int _year;
  int _month;
  int _day;
  int* _a; //指向一块空间
};
int main()
{
  Date d; 
  Date d1(d); //拷贝d的值
}

结果:d对象和d1对象的数据会一模一样,如下图

我们发现d对象的值和d1对象的值一模一样,并且d对象中的_a和d1对象中的_a都指向同一块空间。如下图

上述就值浅拷贝的坏处,d1对象的_a并没有申请资源而是直接指向了d对象_a的空间,如果想让d1

_a也申请空间就需要深拷贝,想要深拷贝就需要自己定义一个拷贝构造函数,该拷贝构造函数如何申请空间要根据不同的场景具体实现。

深拷贝

下面的代码是对上面代码的改造,

class Date
{
public:
 
  Date() //构造函数
  {
    _year = 1;
    _month = 1;
    _day = 1;
      _a = (int*)malloc(sizeof(int) * 7);
      for (int i = 0; i < 7; i++)
      {
        _a[i] = 0;
      }
  }
 
  Date(const Date& d) //拷贝构造函数
  {
    _year = d._year; 
    _month = d._month;
    _day = d._day;
 
    _a = (int*)malloc(sizeof(int) * (sizeof(d._a) / sizeof(d._a[0])));  //开辟空间
 
      for (int i = 0; i < (sizeof(d._a) / sizeof(d._a[0])); i++)  //赋值
      {
        _a[i] = d._a[i];
      }
  }
 
private:
  int _year;
  int _month;
  int _day;
  int* _a;
};
int main()
{
  Date d;
  Date d1(d);
}

d1对象的_a会独自开空间并且拷贝d对象的数据,如下图 这样就完成了拷贝构造的深拷贝了。


小结

拷贝构造是构造函数的重载。参数是该类类型的引用(一般会加上const),不加引用在逻辑是会让拷贝函数无限调用,此时编译器会报错。如果未显示定义拷贝构造函数,编译器会生成默认的拷贝构造函数默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。浅拷贝又称值拷贝,是按字节序拷贝的,通俗的讲别的数据长啥样就拷贝啥样。而深拷贝会申请资源(空间)再赋值。


相关文章
|
8天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
35 4
|
2月前
|
C++
C++(八)拷贝构造器
拷贝构造器用于根据已存在的对象创建新对象。其格式固定,系统提供默认的浅拷贝构造器。浅拷贝仅复制指针而非指针指向的对象,适用于所有数据位于栈上的情况;若类中包含堆数据,则需自定义深拷贝以避免多次析构问题。拷贝构造器在对象复制、作为参数或返回值时被调用。示例展示了拷贝构造器的应用及浅拷贝与深拷贝的区别。
|
6月前
|
编译器 C++ 容器
【C++11特性篇】探究【右值引用(移动语义)】是如何大大提高效率?——对比【拷贝构造&左值引用】
【C++11特性篇】探究【右值引用(移动语义)】是如何大大提高效率?——对比【拷贝构造&左值引用】
|
存储 编译器 C++
【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载
【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载
53 0
【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载
|
6月前
|
C++
C++中拷贝构造会出现的情况
C++中拷贝构造会出现的情况
32 3
|
6月前
|
编译器 C++ 索引
【C++类和对象】拷贝构造与赋值运算符重载(下)
【C++类和对象】拷贝构造与赋值运算符重载
|
6月前
|
存储 编译器 C++
【C++类和对象】拷贝构造与赋值运算符重载(上)
【C++类和对象】拷贝构造与赋值运算符重载
|
6月前
|
数据安全/隐私保护 C++
C++ 构造函数实战指南:默认构造、带参数构造、拷贝构造与移动构造
C++中的构造函数是特殊成员函数,用于对象初始化。类型包括默认构造函数(无参数)、带参数构造函数、拷贝构造函数和移动构造函数。默认构造函数设置对象默认状态,带参数构造函数允许传递初始化值。拷贝构造函数复制已有对象,移动构造函数高效转移资源。构造函数的访问权限可控制为public、private或protected。理解构造函数有助于编写健壮的C++代码。关注公众号`Let us Coding`获取更多内容。
92 0
|
存储 编译器 C语言
【C++基础】类与对象(中):默认成员函数、构造函数、析构函数、拷贝构造、赋值重载函数……
【C++基础】类与对象(中):默认成员函数、构造函数、析构函数、拷贝构造、赋值重载函数……
86 0
|
编译器 C++
【C++基础(六)】类和对象(中) --拷贝构造,运算符重载(下)
【C++基础(六)】类和对象(中) --拷贝构造,运算符重载(下)