Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3425308
  • 博文数量: 198
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7246
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-23 18:56
个人简介

将晦涩难懂的技术讲的通俗易懂

文章分类

全部博文(198)

文章存档

2023年(9)

2022年(4)

2021年(12)

2020年(8)

2019年(18)

2018年(19)

2017年(9)

2016年(26)

2015年(18)

2014年(54)

2013年(20)

分类: C/C++

2014-03-27 00:25:11

在讨论C++函数参数之前,我们先来看一下C程序是如何调用函数的。


如图,为C语言的函数调用记录,C++也类似。当有如下函数:

void fooX x0);

如果有如下调用方式:

X xx;

foo(xx);

    编译器(对于C)会将实参xx以“位逐次拷贝”方式复制给形参x0(注:X0在上图函数活动记录的参数位置)。在C++中,如果一个Class也展现了“位逐次拷贝语义”1,且用户没有定义拷贝构造函数,那么编译器按照这种方式进行拷贝没有问题。但是当一个Class不展现“位逐次拷贝语义”的情况(四种),或者用户定义了拷贝构造函数呢?这种情况编译器必须采用一定措施避免这种直接拷贝的发生(否则拷贝构造函数将不能发生作用)。C++编译器是这样做的:

     调用函数前,先引入一个X的临时变量temp,并以实参xx为参数调用拷贝构造函数(这由编译器安插代码完成)如:

X temp(此处不调用构造函数,只分配空间)

temp.X::X(xx);(这两行代码是由编译器插入)

    之后怎么办呢?如果直接foo(temp),问题又回到之前了,因为只是相当于temp变成了实参,实参到形参x0的拷贝依然是“位逐次拷贝”。所以C++编译器必须做第二个转化,修改函数foo的声明,将其修改为:

void foo(X& x0);

即函数参数变为引用,传入的将是temp的地址。

测试:


点击(此处)折叠或打开

  1. class X
  2. {
  3. public:
  4. X()
  5. {cout<<"X()"<<endl;};
  6. X(const X& x)
  7. {
  8.   cout<<"X(const X& x)"<<endl;
  9. }
  10. X& operator=(const X&)
  11. {
  12.    cout<<"="<<endl;
  13. }
  14. ~X()
  15. {cout<<"destructor"<<endl;}
  16. };
  17. void foo(X x0)
  18. {
  19. }
  20. int _tmain(int argc, _TCHAR* argv[])
  21. {
  22. X xx;
  23. foo(xx);
  24. }

运行结果:


可以看出函数参数的传入需要调用拷贝构造函数构建一个临时对象(注:并不是构建形参,形参已经被转化为引用,不再是对象),另外临时对象在函数退出时销毁。

总结:函数形参中,对象值传递的方式都转化为临时对象和引用传递。

1】一个类不展现“位逐次拷贝”的四种情况:

(1) 这个类有member object,并且这个member object对应的Class定义了拷贝构造函数。

(2) 这个类的父类定义了拷贝构造函数。

(3) 这个类中有虚函数(包括其父类有的情况)。

(4) 这个类的继承连中有虚基类。

阅读(5257) | 评论(0) | 转发(4) |
给主人留下些什么吧!~~