关于拷贝构造函数和运算符重载的问题

各位,最近看了单例模式,里面为了防止单例模式初始化,于是将复制构造函数和重载运算符接口函数全部封掉了。那么这里就有一个问题:到底什么是复制构造函数?什么是运算符重载函数呢?今天查了一些资料,做了一些总结。

一、拷贝构造函数的缺点

二、复制构造函数的结构

三、运算符重载函数的结构

四、总结

一、拷贝构造函数的缺点

  我们首先要复习一下拷贝构造函数。所谓拷贝构造函数,它的目标就是为了复制一些值给新的对象中,比如:

  CExample(int b)

  {a = b}

  主函数当中调用:

  CExample B = A

OK,那么现在我提出一个需求,我们不传递参数了,我们来传递类,那么我们就可以将其改成如下形式。

  假如我们目前有一个类:

  class Test

  {

  };

  那么如果我们要写拷贝构造函数应该怎么写呢?

  CExample(Test b)

       {

  }

  主函数当中调用

  CExample b = a;

  OK,如果你这么写,恭喜你就写错了,因为这样做导致的结果就是会一直调拷贝构造函数,一直到栈溢出。这里要说明的是,他不是再运行当中出现问题,而是再编译当中就报错了,估计可能是编译器的设置有所不同吧。

  也就是说,关于类之间传递的拷贝构造函数我们要重新进行思考和设计。

  而关于类之间传递的拷贝构造函数我们可以分成两个部分:第一种就是再创建的时候就用进行拷贝构造,第二种就是再中间的时候进行拷贝构造。

  第一种举例:CExample b = a;

       第二种举例:CExample b;

                             b = a;

  好的,那么关于复制构造函数和运算符函数重载就是针对这两个问题来进行设计的。

  二、关于复制构造函数

  复制构造函数时专门为了初始化时候传递类来进行设置的,它的设计就是再内部参数当中加上引用即可。即:

       CExample(Test &b)

       {

  }

  三、关于运算符重载函数的问题

    运算符重载函数的作用就是将一些固有的运算符转换成相对应的函数。比如我们可以重载‘+’,‘=’等等方法。那么针对上述问题,我们的解决方案就是重载=运算符。那么它到底有什么用呢?

    这个函数的作用是当运行到上述第二个例子的时候,我们可以使其重载到这个函数中。我们可以重新写这个函数。那么这个函数究竟有什么作用呢?首先要声明一个事实,如果说我们的类中变量中如果没有指针,只有一些具体的数据(比如 int num)的话我们根本就不需要用这个函数。但是如果有指针的话我们就非得使用这个指针了。这是为什么呢?因为如果我们使用指针那么一定需要程序的某一处使用malloc或者new来申请空间,而此处的空间是需要我们手动来进行清除掉的,所以我们一般再析构函数中需要添加delete。而如果我们按照上述第二种方式对其进行赋值,那么仅仅只是对其进行浅拷贝,换句话说,它仅仅只是把指针复制过来了,而实际上指向的内容是一个部分。而两个类最终都会调取析构函数,这样导致的结果就是这段空间析构了两次,结果肯定是进行段错误了。

    那么这个事情怎么办呢?最好的方法就是对其进行重载了,换句话说,只要再重载函数重新开辟一段地址空间,使其两个指针指向两个空间就可以了。它的固定格式为:

    class  class::operator = (const class &)这样的一种形式。

    举个例子,我们以实现一个拷贝字符串为例:

    假如我们现在有一个类是这样的:

    class CopyConstructor
    {
    private:
         char *p;     //字符串的首地址
    public:
       CopyConstructor(char *str);
          virtual ~CopyConstructor();
          CopyConstructor(CopyConstructor &m_copCon);
       CopyConstructor operator = (const CopyConstructor &m_copCon);
 
               void print();
    };
    那么,我们再构造函数当中应该怎么写呢?我想至少应该有这两句话
    p = new char[strlen(str) + 1];    //初始化p的指针,分配空间
              strncpy(p, str, strlen(str) + 1);   //将str的内容拷贝进入p中
    那么析构函数应该怎么写呢?我想至少应该有这几句话
    if (NULL != p)
         {
                 delete p;
            p = NULL;
       }
    好的,如果我们要在运行当中对其进行赋值而且没有重载等号运算符这个函数的话,那么肯定会报段错误,这是因为虽然指针不为空,但是实际上delete了两次。所以会挂掉的,因此我们必须要重写运算符重载函数。    
    CopyConstructor CopyConstructor::operator = (const CopyConstructor &m_copCon)
    {
      p = new char[strlen(m_copCon.p) + 1];
      strncpy(p, m_copCon.p, strlen(m_copCon.p) + 1);
      return *this;
    }
   
 

  四、总结

  总结一下,复制构造函数和运算符重载函数的共同点在于都是用在类的实例化对象进行传递,不同点在于复制构造函数用来再类的初始化的时候进行调用,运算符重载函数是专门为了到中间时来进行调用。

原文地址:https://www.cnblogs.com/songyuchen/p/12896074.html