拷贝构造函数的调用
拷贝构造函数会在以下三中情况下被调用(1)当类的一个对象去初始化该类的另一个对象时 int main(){ Point a(1,2); Point b(a);//用对象a初始化对象b,拷贝构造被调用 Point c=a;//用对象a初始化对象c,拷贝构造被调用 return 0;}细节:上面两种只是写法形式上不一样,执行的操作完全一样(2)如果函数的形参是类的对象,调用函数时,进行形参和实参的结合void(Point p){ cout<<p.getX()<<endl;}int main(){ Point a(1,2); f(a);//函数的形参为类的对象,当调用函数时,拷贝构造函数被调用 return 0;}细节:只有对象用值传递时,才会调用拷贝构造,就像上面的那样。如果用传递引用,则不会调用拷贝构造,即Point &p就不会拷贝构造,这样也会减少时间的调用,效率也会比较高,多采用这种形式。(3)如果函数的返回值是类的对象,函数执行完成返回调用者时Point g(){ Point a(1,2); return a;//函数的返回值是类的对象,返回一个对象时会调拷贝构造}int main(){ Point b; b=g(); return 0;}细节:表面上函数g将a返回给了主函数,但是a是g()的局部对象,离开建立它的函数g以后就消亡了,不可能在返回主函数后继续生存。所以在处理这种情况时编译系统在主函数中创建一个无名临时对象,该临时对象的生存期只在函数调用处的表达式中。也就是表达式“b=g()”中,执行语句"return a;时,实际上是调用拷贝构造将a的值复制到临时对象中。函数g运行结束时对象a消失,但临时对象会存在于表达式"b=g()”中。计算完这个表达式后,临时对象的使命也就完成了,该临时对象便自动消失。这里第三种情况有点特别会生成临时对象,接下来就是throw和return这里的相似的特性。
throw可以抛出的类型是 int、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型。
看一个习题
#include<iostream>using namespace std;class Base
{ public: Base() { cout<<1; } Base(Base&b){ cout<<2; } ~Base() { cout<<3; } }; int f(int a,int b) { if(b==0) { Base b; throw b; } else return a/b;}int main(){ try { cout<<f(9,0); } catch(Base b) { cout<<4; }}//VC下运行结果1223433//CB下运行结果1232433主要说一下在CB下的那种情况,编译器不一样那在这种创建临时对象的情况下优化的也就不一样。
主函数里try去调用函数f然后在f中b==0,创建一个对象b,调构造函数输出1,throw b,与return很相似,创建临时对象,调拷贝构造输出2,然后离开函数f,调析构函数,f里的b析构了输出3,到catch 把临时对象初始化形参b,调拷贝构造输出2,然后输出4,主函数结束,临时对象和形参b都析构输出两次2,即1232433。 小结:在对于返回和抛出一个对象的时候其实throw和return的相似度很高,内部的操作也十分相似。