拷贝构造函数的使用

    技术2022-05-11  75

    一.为什么会有拷贝构造函数

    #include  < fstream > #include  < string > using   namespace  std;ofstream  out ( " HowMany.out " ); class  HowMany{ private :        static   int  objectCount; public :       HowMany() { objectCount ++ ; }        static   void  print( const   string &  msg = "" )       {            if (msg.size() != 0 )                  out << msg << " " ;            out << " objectCount=  " << objectCount << endl;       }        ~ HowMany()       {            objectCount -- ;            print( " ~Howmany() " );        }}; int  HowMany::objectCount = 0 ;HowMany f(HowMany x){     x.print( " x argument inside f() " );     return  x;} int  main(){      HowMany h;      HowMany::print( " after construction of h " );      HowMany h2 = f(h);      HowMany::print( " after call to f() " );}

            这里是上面的代码的输出:                after construction of h: objectCount= 1               x argument inside f(): objectCount= 1               ~Howmany(): objectCount= 0               after call to f(): objectCount= 0               ~Howmany(): objectCount= -1               ~Howmany(): objectCount= -2

          为什么会出现这种情况呢?一定是什么地方出了问题。很明显是在函数f 里面。      它是按值传递的参数,这样就会得到原来对象的一份拷贝,是临时的对象,出了f 的范围这个拷贝自动调用析构销毁,并且将对象计数objectCount减一。但是在传递参数的时候调用构造函数时应该将对象计数objectCount加一的啊,这里却没有。说明在函数传递参数的时候没用调用构造函数,而是用的另外一种方式传递的参数,就是拷贝构造函数。

     二.怎么用拷贝构造函数

          当通过按值传递的方式传递一个对象时,就创立了一个新对象。在下面三种情况会用拷贝构造函数来初始化对象。         1. 函数参数按值传递  (和上面那个例程一样)         2. 返回一个对象来初始化另外一个对象                      HowMany f(HowMany t);             //函数f 返回HowMany对象                      HowMany h1;                      HowMany h2=f(h1);         3. 直接调用拷贝构造函数                       HowMany  h1;                       HowMany  h2(h1);    拷贝构造函数和普通的构造函数差不多,都是以类的名字为函数名,无返回值,只是参数有些不同。       形式为 X(X&)

    #include  < fstream > #include  < string > using   namespace  std;ofstream  out ( " HowMany2.out " ); class  HowMany2{ private :      string  name;      static   int  objectCount; public :     HowMany2( const   string &  id = "" ):name(id)     {           ++ objectCount;          print( " HowMany2() " );     }      void  print( const   string &  msg = "" const      {             if (msg.size() != 0 )                  out << msg << endl;             out << " " << name << " " << " objectCount =  " << objectCount << endl;     }     HowMany2( const  HowMany2 &  h)     {            name = h.name;            name += "  copy " ;             ++ objectCount;            print( " HowMany2(const HowMany2&) " );      }       ~ HowMany2()      {             objectCount -- ;             print( " ~Howmany2() " );      }}; int  HowMany2::objectCount = 0 ;HowMany2 f(HowMany2 x){       x.print( " x argument inside f() " );        out << " Returning from f() " << endl;        return  x;} int  main(){        HowMany2 h( " h " );         out << " Entering f() " << endl;        HowMany2 h2 = f(h);        h2.print( " h2 after call to f() " );         out << " Call f(), no return value " << endl;        f(h);         out << " After call to f() " << endl;        HowMany2 h4(h2);        h4.print( " h4 initial " );}

                 这里演示了上述的三种需要使用拷贝构造函数的情况,大家可以仔细分析一下输出:              HowMany2(const HowMany2&)              h copy: objectCount = 2              x argument inside f()              h copy: objectCount = 2              Returning from f()              HowMany2(const HowMany2&)              h copy copy: objectCount = 3              ~Howmany2()               h copy: objectCount = 2               h2 after call to f()               h copy copy: objectCount = 2              Call f(), no return value              HowMany2(const HowMany2&)              h copy: objectCount = 3              x argument inside f()              h copy: objectCount = 3              Returning from f()              HowMany2(const HowMany2&)              h copy copy: objectCount = 4              ~Howmany2()              h copy copy: objectCount = 3              ~Howmany2()              h copy: objectCount = 2              After call to f()              HowMany2(const HowMany2&)              h copy copy copy: objectCount = 3              h4 initial              h copy copy copy: objectCount = 3              ~Howmany2()              h copy copy copy: objectCount = 2              ~Howmany2()              h copy copy: objectCount = 1              ~Howmany2()              h: objectCount = 0

     三、默认拷贝构造函数

              在我们没有为类建立拷贝构造函数的时候,编译器会自动为新类创建一个默认拷贝构造函数,就如第一个例程,但它使用的是简单位拷贝。就是将原始对象的内存简单复制一份,放在新对象的地址上。但这种位拷贝在出现了继承和组合时会出现很多问题。所以一般在写的类稍复杂一点时,我们就必须添加拷贝构造函数。         不过有时因为初始化很困难,自己很难写出新的拷贝构造函数,而默认拷贝构造函数也不能达到我们的要求,这时我们可以强制编译器不允许按值传递对象,“声明一个私有拷贝构造函数”,甚至不必去定义它。          

    class  NoCC{ private :       int  i;      NoCC( const  NoCC & );           // 私有的拷贝构造函数 public :      NoCC( int  ii = 0 ):i(ii) {}}; void  f(NoCC); int  main(){      NoCC n;      f(n)       // error       NoCC n2 = n;        // error       NoCC n3(n);        // error }    

     

    结语:

            在以后出现了继承和组合时,涉及到类的层次结构,对象的按值传递是一个很麻烦的事情。拷贝构造函数的重要性将会在那里得到体现。就会有深复制和浅复制两种方式来实现拷贝构造函数。

     


    最新回复(0)