拷贝构造函数的使用

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

#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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值