C++中需要创建拷贝构造函数吗?

 

做过C++开发的程序员,很多都觉得不创建拷贝构造函数,似乎也能得到想要的结果。甚至还有人觉得不创建构造函数也可以,当然这是很新很新的新手了。呵呵。

二年前,我也遇到过这个困惑,是不是要显示的创建一个拷贝构造函数。最后还是实践帮我走了迷茫。为了能帮更多的朋友走出困惑,我对自己的理解做了一个总结,虽不够全面,但在某种程度上还是能理解一些问题的。

 

故事描述:现在流行的数码相机代替了传统的胶片相机。数码相机使用了感光元器件,我可以不再使用传统胶片,依然可以成像。基于不同技术,感光元器件(没有查到感光元器件的正确英文单词,暂时使用Photoreceptor代替)分为两种,一种是CMOS,一种是CCD

代码如下:

class CMOS

{

public:

       CMOS()

       {

              len = Coefficient * 35.8;

              width = Coefficient * 23.9;

              printf("%s/n", "Create a CMOS");

       }

 

       CMOS(float Coef)

       {

              Coefficient = Coef;

              len = Coefficient * 35.8;

              width = Coefficient * 23.9;

 

              m_pCompany = new char[6];

              strcpy(m_pCompany, "Canon");

       }

      

       ~CMOS()

       {

        delete m_pCompany;

              printf("%s/n", "Destroy a CMOS");

       }

 

public:

       void Paint()

       {

              printf("%s", "Create a picture by CMOS.");

       }

 

       void PrintSize()

       {

              printf("%s%f/n%s%f/n", "CMOS Length Size:", len, "CMOS Width Size:", width);

       }

 

       void PrintCompany()

       {

              printf("%s%s/n", "Company:", m_pCompany);

       }

public:

       float len;

       float width;

       float Coefficient;

       char *m_pCompany;

};

 

在没有显示定义拷贝构造函数的前提下,测试一下是否可以完成用一个Class Object来初始化另一个Class Object

void main()

{

       CMOS cmos(1.0);

       cmos.PrintSize();

       cmos.PrintAddress();

       cmos.PrintCompany();

 

       CMOS other = coms;

       other.PrintSize();

       other.PrintAddress();

       other.PrintCompany();

}

 

输出结果:

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff64  Address of width:0X12ff68

Address of m_pCompany:0x430070

Company:Canon

 

 

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff50  Address of width:0X12ff54

Address of m_pCompany:0x430070

Company:Canon

 

通过输出结果可以看出,虽然并没有显示的定义构造函数,但得到了期待的结果。此外,也会发现指针成员并没有被拷贝一份,而是两个类对象同时指向了同一个地址。这会不会因为作用域的问题,而引发程序异常呢?接下来再做一个实验。

 

添加一个函数。

void Fun(CMOS &pram)

{

       CMOS temp(1.5); 

       printf("%s/n", "----Print a infomation of temp object----");

       temp.PrintSize();

       temp.PrintAddress();

       temp.PrintCompany();

      

       pram = temp;

}

修改main函数

void main()

{

       printf("%s/n", "----Print a infomation of frist object----");

       CMOS cmos(1.0);

       cmos.PrintSize();

       cmos.PrintAddress();

       cmos.PrintCompany();

 

    printf("%s/n", "----Print a infomation of copy object----");

       CMOS other(cmos);

       other.PrintSize();

       other.PrintAddress();

       other.PrintCompany();

 

       Fun(cmos);

 

       printf("%s/n", "----Print a infomation of frist object again----");

       cmos.PrintSize();

       cmos.PrintAddress();

       cmos.PrintCompany();

 

    printf("%s/n", "----Print a infomation of copy object again----");

       other.PrintSize();

       other.PrintAddress();

       other.PrintCompany();

}

输出结果:

----Print a infomation of frist object----

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff64  Address of width:0X12ff68

Address of m_pCompany:0x431d80

Company:Canon

 

----Print a infomation of copy object----

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff50  Address of width:0X12ff54

Address of m_pCompany:0x431d80

Company:Canon

 

----Print a infomation of temp object----

CMOS Length Size:53.700001

CMOS Width Size:35.849998

Address of len:0x12fed4  Address of width:0X12fed8

Address of m_pCompany:0x431d40

Company:Canon

 

Destroy a CMOS

----Print a infomation of frist object again----

CMOS Length Size:53.700001

CMOS Width Size:35.849998

Address of len:0x12ff64  Address of width:0X12ff68

Address of m_pCompany:0x431d40

Company:Canon

 

----Print a infomation of copy object again----

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff50  Address of width:0X12ff54

Address of m_pCompany:0x431d80

Company:Canon

 

通过这次输出的结果,可以完全放心了。

 

接下来,我们再测试一下Class Object中含有member Class Object的情况。修改代码如下:

class Information

{

public:

       Information()

       {

              len = 35.8;

              width = 23.9;

 

              m_pCompany = new char[6];

              strcpy(m_pCompany, "Canon");

       }

       ~Information()

       {

              delete m_pCompany;

       }

public:

    void PrintSize()

       {

              printf("%s%f/n%s%f/n", "CMOS Length Size:", len, "CMOS Width Size:", width);

       }

 

       void PrintAddress()

       {

              printf("%s%x  %s%x/n%s%x/n","Address of len:0x", &len, "Address of width:0X", &width, "Address of m_pCompany:0x", m_pCompany);

       }

 

       void PrintCompany()

       {

              printf("%s%s/n/n", "Company:", m_pCompany);

       }

public:

       float len;

       float width;

       char *m_pCompany;

};

 

class CMOS

{

public:

       CMOS()

       {

              printf("%s/n", "Create a CMOS");

       }

      

       ~CMOS()

       {

              printf("%s/n", "Destroy a CMOS");

       }

 

public:

       void Paint()

       {

              printf("%s", "Create a picture by CMOS.");

       }

 

       void PrintSize()

       {

              m_Info.PrintSize();

       }

 

       void PrintAddress()

       {

              m_Info.PrintAddress();

       }

 

       void PrintCompany()

       {

              m_Info.PrintCompany();

       }

private:

       Information m_Info;

};

 

void main()

{

     CMOS cmos;

       cmos.PrintSize();

       cmos.PrintAddress();

       cmos.PrintCompany();

 

       CMOS other(cmos);

       other.PrintSize();

       other.PrintAddress();

       other.PrintCompany();

}

输出结果:

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff68  Address of width:0x12ff6c

Address of m_pCompany:0x431d80

Company:Canon

 

CMOS Length Size:35.80000

CMOS Width Size:23.900000

Address of len:0x12ff5c  Address of width:0X12ff60

Address of m_pCompany:0x431d80

Company:Canon

 

这个结果也是另我们满意的,那样是不是说编译器在后台为我们自动生成了一个拷贝构造函数呢?经过参阅资料后得知,其实编译器在上述两种情况并没有合成出来拷贝构造函数,而是采用内存拷贝的方式进行初始化的。

 

上述包含member Class Object的例子中我们并没有显示的定义拷贝构造函数,接下来我们进行显示的定义然后看看程序会怎么样执行。

Information(const Information &Info)

{

len = Info.len;

       width = Info.width;

 

       m_pCompany = new char[6];

       strcpy(m_pCompany, Info.m_pCompany);

}

这次查看程序执行堆栈,结果如下:

Information::Information(const Information & {...}) line 104

CMOS::CMOS(const CMOS & {...}) + 41 bytes

main() line 258 + 12 bytes

 

可以看出,再调用Information类中拷贝构造函数的之前,在CMOS类中合成出了一个拷贝构造函数。

 

到这里,先作一个小结。

前提条件:

1、  参与的类中不涉及Base Class

2、  参与的类中不涉及虚函数。

3、  直接参与类中没有显示的拷贝构造函数。

 

结论:

1、参与的类中不包含member Class Object,边编译器使用内存拷贝的方式完成由一个Class Object初始化另一个Class Object

2、参与的类中包含member Class Object,但是该member Class Object没有显示的拷贝构造函数。边编译器使用内存拷贝的方式完成由一个Class Object初始化另一个Class Object

3、参与的类中包含member Class Object,该member Class Object有显示的拷贝构造函数。边编译器会为直接参与类合成出一个拷贝构造函数,完成由一个Class Object初始化另一个Class Object

 

 

下面为CMOS Object创建一个Base Class

class Photoreceptor

{

public:

       Photoreceptor()

       {

              printf("%s/n", "Create a Photoreceptor");

       }

 

       virtual ~Photoreceptor()

       {

              printf("%s/n", "Destroy a Photoreceptor");

       }

 

public:

       virtual void Paint()

       {

              printf("%s/n", "Create a picture by Photoreceptor.");

       }

};

 

class CMOS : public Photoreceptor

{

public:

       CMOS()

       {

              printf("%s/n", "Create a CMOS");

       }

 

       ~CMOS()

       {

              printf("%s/n", "Destroy a CMOS");

       }

 

public:

       void Paint()

       {

              printf("%s/n", "Create a picture by CMOS.");

       }

}

 

 

void main()

{

     CMOS cmos;

       Photoreceptor ph = cmos;

       cmos.Paint();

       ph.Paint();

}

 

输出结果:

Create a Photoreceptor

Create a CMOS

Create a picture by CMOS.

Create a picture by Photoreceptor.

 

通过输出结果可以发现,这里并没有把cmos对象的虚指针拷贝给ph对象。这需要引起注意。

 

 

那么,我们是不是要为每个类都要创建拷贝构造函数呢?如果类没有Base Class,也没有虚函数,并且只是基础类型的成员变量,这样就不用再构建出来拷贝构造函数了,编译器会出色的完成拷贝任务。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值