拷贝构造函数 参数传递 返回值
来源:互联网 发布:淘宝客卖家后台登陆 编辑:程序博客网 时间:2024/05/14 15:55
一个对象在创建时,一定会调用某个构造函数进行构造。如果函数的参数是以按值传递,则会调用参数类型的拷贝构造函数对形参进行构造;如果返回值是值,则会对返回给函数调用者的对象调用拷贝构造函数进行构造。看下面的使用情况
struct A{ A(){ cout << "A()" << endl; } A(const A&){ cout << "A(const A&)" << endl; } void print(){ cout << "print()" << endl; }}void f(A a){ a.print(); }A g(){ A a; return a; }void h(){ g().print(); }
上面的代码中,f 函数是按值传递,那么当这样子调用函数f 时 ’f(a1)‘ ,f 函数的参数a是如何被构造的呢,就是通过调用拷贝构造函数a(a1)对a进行构造。g()函数是返回一个值,在h()函数中 'g().print()' 的 'g()' 实质上是一个匿名的A对象(假设这个匿名对象叫a1),这个对象是如何被构造的呢,就是通过调用拷贝构造函数a1(a)进行构造的。
返回值
case 1:以下代码没错
struct A{A(){}A(const A&){}};A g(){ const A a; return a; }const A f(){ A a; return a; }case 2:以下代码有错,因为a 是const A类型,那么返回给g()函数的调用者的匿名对象调用的拷贝构造函数是 A(const A&),但该函数未定义。
struct A{A(){}A(A&){}};A g(){ const A a; return a; } // Errorconst A f(){ A a; return a; } // OKcase 3:
struct A{ A(){ cout << "A()" << endl; } A(const A&){ cout << "A(const A&)" << endl; }~A(){ cout << "~A()" << endl; } void print(){ cout << "print()" << endl; }};A g(){ const A a; return a; }int main(){g().print();return 0;}输出
A()
print()
~A()
对于输出,我感到很奇怪。我觉得输出应该是 A() A(const A&) ~A() print() ~A()。我的想法是,g 函数中的a 在g 函数退出时应该就要被析构,所以应该在print 函数前,而a析构前应该要用它作为参数构造返回的匿名对象,所以~A()之前应该有一个A(const A&),而匿名对象在main()函数结束时也应该被析构,所以最后应该也有一个~A()。
虽然上面的输出没有 A(const A&),但是还是有调用拷贝构造函数的,编译器做了优化,没有执行它的函数体,我们可以通过下面的代码进行验证
struct A{ A(){ cout << "A()" << endl; } A(A&){ cout << "A(A&)" << endl; } // changed~A(){ cout << "~A()" << endl; } void print(){ cout << "print()" << endl; }};A g(){ const A a; return a; } // Errorint main(){g().print(); return 0;}当改了拷贝构造函数后,编译通不过,提示找不到拷贝构造函数 A(const A&),原因就是case 2。
继续看下面的代码
struct A{ A(){ cout << "A()" << endl; } A(const A&){ cout << "A(const A&)" << endl; }~A(){ cout << "~A()" << endl; } void print(){ cout << "print()" << endl; }};const A g(){ A a; cout << (void*)(&a) << endl; return a; }void f(const A& a1){ cout << (void*)(&a1) << endl; }int main(){ f(g());}
输出
A()
0x22ac2f
0x22ac2f
~A()
惊奇地发现,a1与a居然在同一地址上,也就是它们是同一个对象。这个时候我们可以大胆地推测,返回值会匹配拷贝构造函数,但是编译器做了优化后不会执行函数体。编译器应该是这样子认为的:析构g 函数中的a,再拷贝构造一个a1,效率不好,还不如把a直接给a1好了。但是要值得注意的是,拷贝构造函数还是一定要严格匹配的,而且虽然a和a1是同一个对象,但是修饰不一样,a是A类型,a1是const A类型,所以a可以调用print函数,a1不能调用print函数。
在 explicit 文章中也提到过, A a = A();只调用了默认构造函数,没有调用拷贝构造函数(但还是匹配拷贝构造函数的原型),编译器应该是认为,A()这个匿名对象,因为匿名的原因,其他地方也无法用到它了,既然要用它来拷贝构造另一个对象,不如把它直接给用一个对象好了。但是,A a = a1;就是调用拷贝构造函数了,因为a1还可能被用到。
但是,当返回的值不是函数声明的返回值类型却有相应该的转换构造函数时,情况怎样?且看下面代码
struct B{B(){ cout << "B()" << endl;}~B(){ cout << "~B()" << endl; }};struct A{ A(){ cout << "A()" << endl; } A(const A&){ cout << "A(const A&)" << endl; }A(const B&){cout << "A(const B&)" << endl; }~A(){ cout << "~A()" << endl; } void print(){ cout << "print()" << endl; }};A g(){ B b; cout << (void*)&b << endl; return b; }void f(const A& a){ cout << (void*)(&a) << endl; }int main() { A a = g();cout << (void*)&a << endl;}输出:
B()
0x22abff
A(const B&)
~B()
0x22ac2f
~A()
可以看出,a与b指向不同的对象了。由上面的代码我们可以进一步肯定,函数function()返回时的一般步骤为
调用相应的构造函数构造function()返回的匿名对象 -> 析构function()中的对象 -> function()结束 -> 主调函数继续执行
- 拷贝构造函数 参数传递 返回值
- C++函数参数,返回值,拷贝构造函数等
- 为什么C++中的拷贝构造函数参数不能值传递
- 对象作为参数和返回值 复制(拷贝)构造函数
- 拷贝构造函数在哪些地方用,函数参数,函数返回值
- 构造函数传递参数
- C++函数参数传递和返回值
- C++函数参数传递和返回值
- 函数参数和返回值的传递
- 函数返回值与参数传递
- 函数参数的传递和值返回
- 拷贝构造函数为什么不能用值传递
- 【翠字营原创】: 函数参数(实参, 虚参)、返回值,类深度拷贝构造、赋值操作符深一步的了解
- 返回值为对象调用拷贝构造函数
- C++构造函数、拷贝构造函数、赋值运算符漫谈(一)——函数参数传递
- C++构造函数、拷贝构造函数、赋值运算符漫谈(一)——函数参数传递
- C++构造函数、拷贝构造函数、赋值运算符漫谈(一)——函数参数传递
- 对象作为函数参数时调用拷贝构造函数、引用做函数参数时只是传递地址
- 《unix高级环境编程》文件和目录——文件操作
- 迷你MVVM框架 avalonjs 学习教程21、双向绑定链
- BZOJ 1787 AHOI2008 紧急集合 倍增LCA
- 浅析linux 2.6.23下kobject如何生成sysfs目录文件
- Linq中jion方法连接集合对象时候,多条件处理
- 拷贝构造函数 参数传递 返回值
- 生物学笔记四(奇特之处)
- 程序填充
- Linux修改用户默认目录的方法
- 卸载oarcle11g
- linux 下mariadb源码包安装
- Python的基础(运算符)
- makefile 模版
- Tornado官方文档,中文翻译(一)