Chinaunix首页 | 论坛 | 博客
  • 博客访问: 458404
  • 博文数量: 72
  • 博客积分: 1851
  • 博客等级: 上尉
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 17:50
文章分类

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: C/C++

2011-04-28 21:59:52

    在c语言中,函数中按值传递且传递的内容都很小,一般都是采用bit复制方式,但是到了C++中,传递的有可能是对象,这样传递的内容就会大大增加,默认也是采用bit复制方式(bit-copy),但是这样就会导致大量的数据被复制,而且更关键的是构造函数不会被调用。如:
  1. #include <fstream>
  2. #include <iostream>
  3. using namespace std;

  4. class HowMany
  5. {
  6. static int objectCount;
  7. int count;
  8. public:
  9. HowMany(){
  10. count=10;
  11. objectCount++;
  12. cout<<"construction is called here!"<<endl;
  13. }
  14. static void print(const string& msg=""){
  15.     if(msg.size()!=0) cout<<msg<<":";
  16.     cout<<"objectCount = "<<objectCount<<endl;
  17. }
  18. void Increase(){
  19. cout<<"before:"<<count;
  20. count++;
  21. cout<<"after "<<count<<endl;
  22. }
  23. void Decrease(){
  24. cout<<"before:"<<count;
  25. count--;
  26. cout<<"after "<<count<<endl;
  27. }
  28. ~HowMany(){
  29. objectCount--;
  30. cout<<"count:"<<count<<endl;
  31. print("~HowMany()");
  32. }
  33. };
  34. int HowMany::objectCount =0;
  35. HowMany f(HowMany x)
  36. {
  37.     //行参被复制传递一次
  38.     x.print("function f is called here");
  39.     return x;
  40. }

  41. int main()
  42. {
  43.     HowMany *h=new HowMany;
  44.     HowMany::print("after construction of h");
  45.     HowMany h2(*h);
  46.     h->Increase();
  47.     h2.Decrease();
  48.     HowMany::print("after call to f()");
  49.     delete h;
  50.     return 0;
  51. }

编译运行上面的代码:


  1. construction is called

  2. after construction of h:objectCount = 1

  3. before:10after 11

  4. before:10after 9

  5. after call to f():objectCount = 1

  6. count:11

  7. ~HowMany():objectCount = 0

  8. count:9

  9. ~HowMany():objectCount = -1

可以看出在调用初始化函数,确实只调用一次,这样h2就没有调用该函数了,一般来讲,如果没有指针的情况下,是可以的,如果含有指针的形式,bit复制就会导致两个对象同时指向一个对象了,如下面的示例:


  1. #include <fstream>

  2. #include <iostream>

  3. /*

  4. *测试C++默认的复制方式:bitcopy

  5. *copy-constructor:当一个新对象(没有初始化)从一个存在的对象中获取数值时

  6. *assignment operator:当已经初始化的对象被赋予新的数值时,被调用

  7. */

  8. using namespace std;

  9. //ofstream out("HowMany.out");

  10. class HowMany

  11. {

  12. static int objectCount;

  13. int *count;

  14. public:

  15. HowMany(){

  16. count = new int;

  17. *count=0;

  18. objectCount++;

  19. cout<<"construction is called here!"<<endl;

  20. }

  21. static void print(const string& msg=""){

  22. if(msg.size()!=0) cout<<msg<<":";

  23. cout<<"objectCount = "<<objectCount<<endl;

  24. }

  25. void Increase(){

  26. cout<<"before:"<<*count;

  27. (*count)++;

  28. cout<<"after "<<*count<<endl;

  29. }

  30. void Decrease(){

  31. cout<<"before:"<<*count;

  32. (*count)--;

  33. cout<<"after "<<*count<<endl;

  34. }

  35. ~HowMany(){

  36. objectCount--;

  37. cout<<"count:"<<*count<<endl;

  38. delete count;

  39. print("~HowMany()");

  40. }

  41. //如果加上一个赋值重载符又会怎么样呢

  42. HowMany& operator= (const HowMany&)

  43. {

  44. cout<<"Operator = is called here!"<<endl;

  45. }

  46. };

  47. int HowMany::objectCount =0;

  48. HowMany f(HowMany x)

  49. {

  50. //行参被复制传递一次

  51. x.print("function f is called here");

  52. return x;

  53. }

  54. int main()

  55. {

  56. HowMany *h=new HowMany;

  57. HowMany::print("after construction of h");

  58. HowMany h2(*h);

  59. h->Increase();

  60. h2.Decrease();

  61. HowMany::print("after call to f()");

  62. return 0;

  63. }

编译上面的代码,就会出现下面的结果:


  1. construction is called

  2. after construction of h:objectCount = 1

  3. before:0after 1

  4. before:1after 0

  5. after call to f():objectCount = 1

  6. count:0

  7. ~HowMany():objectCount = 0

这样两个对象同时指向同一个变量,不包含指针的情况下,不实现copy-constructor是可以的。如果实现copy-constructor,其实也很简单,但是参数的传递是个问题:对象不能通过值传递给构造函数(copy-constructor是构造函数),因为定义的就是处理按值传递,又按值传递,这样就错误了,同样不能进行按指针传递,因为你正在从一个已存在的对象中创建一个新对象,这里只能是引用了,而且只读(const),所以定义为下面的形式:


  1. HowMany(const HowMany&h1){

  2. cout<<"HowMany copy constructor is called here"<<endl;

  3. }

定义了具体的复制函数,系统就会调用处理函数了,但是这样没有处理具体的逻辑的话,执行就会出现运行时错误(bitcopy没有了,内存又没有分配),最好将系统中动态对象进行初始化,而且该与被复制的保持一致的,就保持一致:


  1. HowMany(const HowMany&h1){

  2. cout<<"HowMany copy constructor is called here"<<endl;

  3. count = new int;

  4. *count=0;

  5. }

执行之后,用valgrind检查就会出现明显的内存泄漏,不过调用delete h1之后就正常了。


  1. construction is called here!

  2. after construction of h:objectCount = 1

  3. HowMany copy constructor is called here

  4. before:0after 1

  5. before:0after -1

  6. after call to f():objectCount = 1

  7. count:-1

  8. ~HowMany():objectCount = 0

复制构造函数与赋值(operator=)函数相比较,更轻(构造函数中的初始化列表就是采用了复制构造函数形式)

1.复制构造函数为构造函数,直接初始化对象,而赋值函数需要进行析构原来的对象,再重新构造一个新对象;

2.构造函数不需要进行返回,而赋值函数需要进行返回。

所以如果没有初始化的就最好调用复制构造函数,否则调用赋值函数。另外初始化列表必须在构造函数体前面

,否则由于在构造函数内部,类的成员变量被初始化了,复制构造函数就失效了。

参考资料:

thinking in C++

阅读(1616) | 评论(0) | 转发(0) |
0

上一篇:编译,安装linux内核

下一篇:C++重载

给主人留下些什么吧!~~