详解C++ 拷贝构造函数

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

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

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

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++ 拷贝构造函数的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解C++ 编写String 的构造函数、拷贝构造函数、析构函数和赋值函数

    详解C++ 编写String 的构造函数.拷贝构造函数.析构函数和赋值函数 编写类String 的构造函数.析构函数和赋值函数,已知类String 的原型为: class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &other); // 拷贝构造函数 ~ String(void); // 析构函数 String & operate =(const String &ot

  • c++中拷贝构造函数的参数类型必须是引用

    在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识. 但是如果我问你"拷贝构造函数的参数为什么必须使用引用类型?"这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答.不过还好,我思索一下以后,发现这个答案是不对的. 原因:如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传

  • c/c++拷贝构造函数和关键字explicit详解

    关键字explicit 修饰构造方法的关键字,加上了,就告诉编译器,不可以隐式初始化对象:不加就可以隐式初始化对象: 下面的代码是可以正常编译执行的,但是加了关键字explicit,编译就会错我,因为Test t = 100;是隐式初始化对象,但是如果加上强制类型转换后,就不会有错误了. 强制类型转换:Test t = (Test)100; class Test{ public: Test(int d):data(d){//explicit cout << "C:" <

  • 详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现

    C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法.下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象时,它被调用来对类的数据成员进行初始化和分配内存.(构造函数的命名必须和类名完全相同) 首先说一下一个C++的空类,编译器会加入哪些默认的成员函数 默认构造函数和拷贝构造函数 析构函数 赋值函数(赋值运算符) 取值函数 **即使程序没定义任何成员,编译器也会插入以上的函数! 注意:构造函数可以被重载

  • C++中拷贝构造函数的总结详解

    1.什么是拷贝构造函数: 拷贝构造函数嘛,当然就是拷贝和构造了.(其实很多名字,只要静下心来想一想,就真的是顾名思义呀)拷贝又称复制,因此拷贝构造函数又称复制构造函数.百度百科上是这样说的:拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化.其唯一的参数(对象的引用)是不可变的(const类型).此函数经常用在函数调用时用户定义类型的值传递及返回. 2.拷贝构造函数的形式 复制代码 代码如下: Class X{public: X(); X(const

  • 深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结

    1 . 用同一个类的源对象构造一个目标对象时,会调用拷贝构造函数来构造目标对象,如果没有定义拷贝构造函数,将调用类的默认拷贝函数来构造目标对象.2 . 当一个函数的返回值为一个类的对象时,如果在调用函数中,没有定义一个对象来接收这个返回对象值,会用返回一个临时对象保存返回对象的值.在被调用函数结束时,这个临时对象被销毁.而当调用函数中有一个接受对象时,就将返回对象赋值给接收对象,这个返回对象在调用函数结束时调用析构函数.3. 当类有一个带有一个参数的构造函数时,可以用这个参数同类型的数据初始化这

  • 详解C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义,但是也没有显式的删除),编译器会自动的隐式生成一个拷贝构造函数和赋值运算符.但用户可以使用delete来指定不生成拷贝构造函数和赋值运算符,这样的对象就不能通过值传递,也不能进行赋值运算. class Person { public: Person(const Person& p) = dele

  • 详解C++ 拷贝构造函数

    拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象.拷贝构造函数通常用于: 通过使用另一个同类型的对象来初始化新创建的对象. 复制对象把它作为参数传递给函数. 复制对象,并从函数返回这个对象. 如果在类中没有定义拷贝构造函数,编译器会自行定义一个.如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数.拷贝构造函数的最常见形式如下: classname (const classname &obj) { // 构造函数的主体 } 在这里,o

  • C++中构造函数的参数缺省的详解

    C++中构造函数的参数缺省的详解 前言: 构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值.在构造函数中也可以采用这样的方法来实现初始化. #include <iostream> using namespace std; class A { public : A(int aa=0,int bb=00); //在声明构造函数时指定默认参数 int volume( ); int a; int b; }; int main( ) { A

  • C++编程析构函数拷贝构造函数使用示例详解

    目录 构造函数 析构函数 拷贝构造之深拷贝和浅拷贝 深浅拷贝区别 首先定义一个类进行操作. class MM { public: protected: int year; string name; } 构造函数在类中默认有一个无参的构造函数 默认的构造函数为 类名(){}:这个构造函数 如果直接写了构造函数那么这个构造函数将会没有 构造函数 class MM { public: //MM() {};//无参构造函数 MM(int year, string name) :year(year), n

  • C++中的拷贝构造函数详解

    目录 C++拷贝构造函数(复制构造函数)详解 1) 为什么必须是当前类的引用呢? 2) 为什么是 const 引用呢? 默认拷贝构造函数 总结 C++拷贝构造函数(复制构造函数)详解 拷贝和复制是一个意思,对应的英文单词都是copy.对于计算机来说,拷贝是指用一份原有的.已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据.例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思. 在

  • C++实现拷贝构造函数的方法详解

    目录 引入 一.什么是拷贝构造函数 二.什么情况下使用拷贝构造函数 三.使用拷贝构造函数需要注意什么 四.深拷贝浅拷贝 4.1 浅拷贝 4.2 深拷贝 引入 对于普通类型的对象来说,他们之间的复制很简单: int a = 10;int b = a; 但是对于类对象来说,其中会存在许多的成员变量. #include <iostream> using namespace std; class CExample { private: int a; public: //构造函数 CExample(in

  • C++拷贝构造函数(深拷贝与浅拷贝)详解

    对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. 复制代码 代码如下: #include <iostream>using namespace std; class CExample {private:    int a;public:    CExample(int b)    { a=b;}    void Show ()    {       

随机推荐