"<
return0;
}
13.按值传递和函数返回一个值时,系统自动调用复制构造函数:
#include
usingnamespacestd;
classA
{
public:
A(){cout<<"执行构造函数创建一个对象\n";}
A(A&){cout<<"执行复制构造函数创建该对象的副本\n";}
~A(){cout<<"执行析构函数删除该对象\n";}
};
Afunc(Aone)
{
returnone;
}
intmain()
{
Aa;
func(a);
return0;
}
程序的执行结果是:
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
执行析构函数删除该对象
执行析构函数删除该对象
这是因为:
从主函数开始,创建一个对象a时,系统自动调用构造函数,打印"执行构造函数创建一个对象";调用函数func(a)把a的值传递过去,这是系统会自动调用复制构造函数,打印"执行复制构造函数创建该对象的副本";当func()函数执行完毕,返回一个值时,系统再次调用复制构造函数,打印"执行复制构造函数创建该对象的副本";用于func()函数的返回值没有被接收,返回值被丢弃,并且该返回值是一个对象,所以系统自动调用析构函数释放该对象所占的内存,打印"执行析构函数删除该对象";func()函数执行完毕,系统会自动调用析构函数释放该函数的参数中定义的对象,打印"执行析构函数删除该对象";func()函数执行完毕后,回到主函数,在主函数即将结束前的那一秒,系统再次调用析构函数,释放a对象所占的内存空间,打印"执行析构函数删除该对象".如果是按址传递:
#include
usingnamespacestd;
classA
{
public:
A(){cout<<"执行构造函数创建一个对象\n";}
A(A&){cout<<"执行复制构造函数创建该对象的副本\n";}
~A(){cout<<"执行析构函数删除该对象\n";}
};
Afunc(A*one)
{
return*one;
}
intmain()
{
Aa;
func(&a);
return0;
}
程序的执行结果是:
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
执行析构函数删除该对象
这是因为:
从主函数开始,创建一个对象a时,系统自动调用构造函数,打印"执行构造函数创建一个对象";调用函数func(&a)把a的地址传递过去,这时系统不会调用复制构造函数,所以不打印"执行复制构造函数创建该对象的副本";当func()函数执行完毕,返回一个值时,系统自动调用复制构造函数,打印"执行复制构造函数创建该对象的副本";用于func()函数的返回值没有被接收,返回值被丢弃,并且该返回值是一个对象,所以系统自动调用析构函数释放该对象所占的内存,打印"执行析构函数删除该对象";func()函数执行完毕后,回到主函数,在主函数即将结束前的那一秒,系统再次调用析构函数,释放a对象所占的内存空间,打印"执行析构函数删除该对象".如果是按地址传递并且返回地址:
#include
usingnamespacestd;
classA
{
public:
A(){cout<<"执行构造函数创建一个对象\n";}
A(A&){cout<<"执行复制构造函数创建该对象的副本\n";}
~A(){cout<<"执行析构函数删除该对象\n";}
};
A*func(A*one)
{
returnone;
}
intmain()
{
Aa;
func(&a);
return0;
}
程序的执行结果是:
执行构造函数创建一个对象
执行析构函数删除该对象
这是因为:
从主函数开始,创建一个对象a时,系统自动调用构造函数,打印"执行构造函数创建一个对象";在主函数即将结束前的那一秒,系统调用析构函数,释放a对象所占的内存空间,打印"执行析构函数删除该对象".
按别名来传递对象:
classA
{
public:
A(){cout<<"执行构造函数创建一个对象\n";}
A(A&){cout<<"执行复制构造函数创建该对象的副本\n";}
~A(){cout<<"执行析构函数删除该对象\n";}
voidset(inti){x=i;}
intget()const{returnx;}
private:
intx;
};
A&func(A&one)
{
returnone;
}
intmain()
{
Aa;
a.set(11);
A&b=func(a);
cout<return0;
}
程序的执行结果是:
执行构造函数创建一个对象
11
执行析构函数删除该对象
按别名来传递对象不调用复制构造函数
程序改为:
classA
{
public:
A(){cout<<"执行构造函数创建一个对象\n";}
A(A&){cout<<"执行复制构造函数创建该对象的副本\n";}
~A(){cout<<"执行析构函数删除该对象\n";}
voidset(inti){x=i;}
intget()const{returnx;}
private:
intx;
};
A&func(A&one)
{
returnone;
}
intmain()
{
Aa;
a.set(11);
A&b=func(a);
cout<b.set(33);
cout<return0;
}
程序的执行结果是:
执行构造函数创建一个对象
11
33
执行析构函数删除该对象
若程序改为:
classA
{
public:
A(){cout<<"执行构造函数创建一个对象\n";}
A(A&){cout<<"执行复制构造函数创建该对象的副本\n";}
~A(){cout<<"执行析构函数删除该对象\n";}
voidset(inti){x=i;}
intget()const{returnx;}
private:
intx;
};
constA&func(A&one)
{
returnone;
}
intmain()
{
Aa;
a.set(11);
constA&b=func(a);
cout<//b.set(33);//执行这条语句会报错,因为b是一个常量的对象的别名
return0;
}
14.栈区(stack)由编译器自动分配并且释放,该区域一般存放函数的参数值、局部变量的值、局部对象的值和引用等,并且该区中的数据的寿命是到方法结束返回时;堆区(heap)用于存放引用类型和基本数据类型new出来的内存,该内存由程序员分配并且释放,若程序员不释放,要等到程序结束后操作系统才回收,堆是采用匿名的方式来保存数据的,只有通过指针才能访问到这些匿名的数据,自由度最高、安全性最好;寄存器区用来保存栈顶指针和指令指针;全局区又称静态区(static),在静态区中存放的是全局变量和静态变量,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和静态变量在相邻的令一块区域,程序结束后静态区由系统释放;文字常量区用于存放常量字符串,程序结束后由系统释放;程序代码区存放函数体的二进制代码.(静态方法中不能引用非静态成员,且在该方法中不能使用this关键字)
15.创建一个堆:
int