拷贝构造函数专题(面试直播)

【1】拷贝有两种:深拷贝,浅拷贝。

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

【2】深拷贝与浅拷贝的区别就在于

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

【3】拷贝构造函数的几个细节

1.为什么拷贝构造函数必须是引用传递,不能是值传递?

 简单的回答是为了防止递归引用。
 具体一些可以这么讲:
 当 一个对象需要以值方式传递时,编译器会生成代码调用它的拷贝构造函数以生
 成一个复本。如果类A的拷贝构造函数是以值方式传递一个类A对象作为参数的话
 ,当 需要调用类A的拷贝构造函数时,需要以值方式传进一个A的对象作为实参;
  而以值方式传递需要调用类A的拷贝构造函数;结果就是调用类A的拷贝构造函数
  导 致又一次调用类A的拷贝构造函数,这就是一个无限递归。

2.拷贝构造函数的作用。

 作用就是用来复制对象的,在使用这个对象的实例来初始化这个对象的一个新的实例。

3.参数传递过程到底发生了什么?

  将地址传递和值传递统一起来,归根结底还是传递的是"值"(地址也是值,只不过通过它可以找到另一个值)
  
  a)值传递:
     对于内置数据类型的传递时,直接赋值拷贝给形参(注意形参是函数内局部变量);
     对于类类型的传递时,需要首先调用该类的拷贝构造函数来初始化形参(局部对象);
     如void foo(class_type obj_local){}, 如果调用foo(obj);  首先class_type obj_local(obj) 
     ,这样就定义了局部变量obj_local供函数内部使用
     
 b)引用传递:
    无论对内置类型还是类类型,传递引用或指针最终都是传递的地址值!而地址总是
    指针类型(属于简单类型), 显然参数传递时,按简单类型的赋值拷贝,而不会有拷贝
    构造函数的调用(对于类类型).

4.在类中有指针数据成员时,拷贝构造函数的使用?

      如果不显式声明拷贝构造函数的时候,编译器也会生成一个默认的拷贝构造函数,
      而且在一般的情况下运行的也很好。但是在遇到类有指针数据成员时就出现问题 
      了:因为默认的拷贝构造函数是按成员拷贝构造,这导致了两个不同的指针(如ptr1=ptr2)
      指向了相同的内存。当一个实例销毁时,调用析构函数 free(ptr1)释放了这段内存
      ,那么剩下的一个实例的指针ptr2就无效了,在被销毁的时候free(ptr2)就会出现
      错误了, 这相当于重复释放一块内存两次。这种情况必须显式声明并实现自己的
      拷贝构造函数,来为新的实例的指针分配新的内存。

问题1和2回答了为什么拷贝构造函数使用值传递会产生无限递归调用的问题;
问题3回答了回答了在类中有指针数据成员时,拷贝构造函数使用值传递等于白显式定义了拷贝构造函数,因为默认的拷贝构造函数就是这么干的。

5.拷贝构造函数里能调用private成员变量吗?

解答:这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时
就是一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。

【4】C++构造函数以及析构函数的若干面试问题

Q1:构造函数能否重载,析构函数能否重载,为什么?

扫描二维码关注公众号,回复: 6543509 查看本文章
 A1:构造函数可以,析构函数不可以。

Q2:析构函数为什么一般情况下要声明为虚函数?

  A2:虚函数是实现多态的基础,当我们通过基类的指针是析构子类对象时候,
  如果不定义成虚函数,那只调用基类的析构函数,子类的析构函数将不会被调
  用。如果定义为虚函数,则子类父类的析构函数都会被调用。

Q3:什么情况下必须定义拷贝构造函数?

  A3:当类的对象用于函数值传递时(值参数,返回类对象),拷贝构造函数会被调用。
  如果对象复制并非简单的值拷贝,那就必须定义拷贝构造函数。例如大的堆栈数据拷
  贝。如果定义了拷贝构造函数,那也必须重载赋值操作符。

【5】什么时候必须重写拷贝构造函数

1、这里有个简单的规则:如果你需要定义一个非空的析构函数,那么,通常情况下你也需要定义一个拷贝构造函数。
2、有一个原则:一般来说你在类中进行了new操作,你就需要析构函数,在你需要析构函数的类中,一般需要加上
挎贝构造函数和赋值函数。
3、拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其
唯一的参数(对象的引用)是不可变的(const类型)。此函数经常用在函数调用时用户定义类型的值传递及返回。
拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常
量方式调用。
在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):

  1) 一个对象作为函数参数,以值传递的方式传入函数体;

  2) 一个对象作为函数返回值,以值传递的方式从函数返回;

  3) 一个对象用于给另外一个对象进行初始化(常称为复制初始化);

通常的原则是:①对于凡是包含动态分配成员或包含指针成员的类都应该提供拷贝构造函数;
②在提供拷贝构造函数的同时,还应该考虑重载"="赋值操作符号。

猜你喜欢

转载自blog.csdn.net/N1314N/article/details/91125969