详解C++ 拷贝构造函数

所属分类: 软件编程 / C 语言 阅读数: 71
收藏 0 赞 0 分享

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。
  • 复制对象把它作为参数传递给函数。
  • 复制对象,并从函数返回这个对象。

如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下:

classname (const classname &obj) {
  // 构造函数的主体
}

在这里,obj 是一个对象引用,该对象是用于初始化另一个对象的。

#include <iostream>
 
using namespace std;
 
class Line
{
  public:
   int getLength( void );
   Line( int len );       // 简单的构造函数
   Line( const Line &obj);   // 拷贝构造函数
   ~Line();           // 析构函数
 
  private:
   int *ptr;
};
 
// 成员函数定义,包括构造函数
Line::Line(int len)
{
  cout << "调用构造函数" << endl;
  // 为指针分配内存
  ptr = new int;
  *ptr = len;
}
 
Line::Line(const Line &obj)
{
  cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
  ptr = new int;
  *ptr = *obj.ptr; // 拷贝值
}
 
Line::~Line(void)
{
  cout << "释放内存" << endl;
  delete ptr;
}
int Line::getLength( void )
{
  return *ptr;
}
 
void display(Line obj)
{
  cout << "line 大小 : " << obj.getLength() <<endl;
}
 
// 程序的主函数
int main( )
{
  Line line(10);
 
  display(line);
 
  return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

调用构造函数
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
释放内存

下面的实例对上面的实例稍作修改,通过使用已有的同类型的对象来初始化新创建的对象:

#include <iostream>
 
using namespace std;
 
class Line
{
  public:
   int getLength( void );
   Line( int len );       // 简单的构造函数
   Line( const Line &obj);   // 拷贝构造函数
   ~Line();           // 析构函数
 
  private:
   int *ptr;
};
 
// 成员函数定义,包括构造函数
Line::Line(int len)
{
  cout << "调用构造函数" << endl;
  // 为指针分配内存
  ptr = new int;
  *ptr = len;
}
 
Line::Line(const Line &obj)
{
  cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
  ptr = new int;
  *ptr = *obj.ptr; // 拷贝值
}
 
Line::~Line(void)
{
  cout << "释放内存" << endl;
  delete ptr;
}
int Line::getLength( void )
{
  return *ptr;
}
 
void display(Line obj)
{
  cout << "line 大小 : " << obj.getLength() <<endl;
}
 
// 程序的主函数
int main( )
{
  Line line1(10);
 
  Line line2 = line1; // 这里也调用了拷贝构造函数
 
  display(line1);
  display(line2);
 
  return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

调用构造函数
调用拷贝构造函数并为指针 ptr 分配内存
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
释放内存
释放内存

关于为什么当类成员中含有指针类型成员且需要对其分配内存时,一定要有总定义拷贝构造函数??

默认的拷贝构造函数实现的只能是浅拷贝,即直接将原对象的数据成员值依次复制给新对象中对应的数据成员,并没有为新对象另外分配内存资源。

这样,如果对象的数据成员是指针,两个指针对象实际上指向的是同一块内存空间。

在某些情况下,浅拷贝回带来数据安全方面的隐患。

当类的数据成员中有指针类型时,我们就必须定义一个特定的拷贝构造函数,该拷贝构造函数不仅可以实现原对象和新对象之间数据成员的拷贝,而且可以为新的对象分配单独的内存资源,这就是深拷贝构造函数。

如何防止默认拷贝发生

声明一个私有的拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类的对象,编译器会报告错误,从而可以避免按值传递或返回对象。

总结:

当出现类的等号赋值时,会调用拷贝函数,在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象。所以,这时,必须采用深拷贝。

深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝。

以上就是详解C++ 拷贝构造函数的详细内容,更多关于C++ 拷贝构造函数的资料请关注脚本之家其它相关文章!

更多精彩内容其他人还在看

C语言数组入门之数组的声明与二维数组的模拟

这篇文章主要介绍了C语言数组入门之数组的声明与二维数组的模拟,数组学习的同时也要相应理解C语言指针的作用,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中变量与其内存地址对应的入门知识简单讲解

这篇文章主要介绍了C语言中变量与其内存地址对应的入门知识简单讲解,同时这也是掌握指针部分知识的基础,需要的朋友可以参考下
收藏 0 赞 0 分享

讲解C语言编程中指针赋值的入门实例

这篇文章主要介绍了讲解C语言编程中指针赋值的入门实例,通过const int i与int *const pi这样两个例子来分析指针的赋值和地址指向,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中的结构体的入门学习教程

这篇文章主要介绍了C语言中的结构体的入门学习教程,以struct语句定义的结构体是C语言编程中的重要基础,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程入门之程序头文件的简要解析

这篇文章主要介绍了C语言编程入门之程序头文件的简要解析,包括头文件重复包含问题等方面的说明,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程中的联合体union入门学习教程

这篇文章主要介绍了C语言编程中的联合体union入门学习教程,也是C语言入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中数组作为函数的参数以及返回值的使用简单入门

这篇文章主要介绍了C语言中数组作为函数的参数以及返回值的使用简单入门,这里以一维数组作为基本条件进行例子讲解,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL的内存表的基础学习教程

这篇文章主要介绍了MySQL的内存表的基础学习教程,包括内存表的创建以及使用限制等等,需要的朋友可以参考下
收藏 0 赞 0 分享

C++中头文件的概念与基本编写方法

这篇文章主要介绍了C++中头文件的概念与基本编写方法,是C++入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

jQuery移动页面开发中主题按钮的设计示例

这篇文章主要介绍了jQuery移动页面开发中主题按钮的设计示例,jQuery是当今最具人气的JavaScript开发类库,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多