第六讲:构造拷贝析构
- 拷贝构造函数
- 析构函数
- 构造函数与析构函数的执行顺序
拷贝构造函数
- 拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用
class 类名 {
public :
类名(形参);//构造函数
类名(类名 &对象名);//拷贝构造函数
...
};
类名::类(类名 &对象名)//拷贝构造函数的实现
{ 函数体 }
class Point {
public:
Point(int xx=0, int yy=0) { x = xx; y = yy; }
Point(Point& p);
int getX() { return x; }
int getY() { return y; }
private:
int x, y;
};
Point::Point (Point& p) {
x = p.x;
y = p.y;
cout << "Calling the copy constructor " << endl;
}
当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值
int main() {
Point a(1,2);
Point b = a; //拷贝构造函数被调用
cout << b.getX() << endl;
}若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数
void fun1(Point p) {
cout << p.getX() << endl;
}
int main() {
Point a(1, 2);
fun1(a); //调用拷贝构造函数
return 0;
}
- 当函数的返回值是类对象时,系统自动调用拷贝构造函数,例如:
Point fun2() {
Point a(1, 2);
return a; //调用拷贝构造函数
}
int main() {
Point b;
b = fun2();
return 0;
}
- 隐含的拷贝构造函数
- 如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个隐含的拷贝构造函数。
- 这个构造函数执行的功能是:用作为初始化值的对象的每个数据成员的值,初始化将要建立的对象的对应数据成员。
析构函数
- 完成对象被删除前的一些清理工作
- 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。
如果程序中未声明析构函数,编译器将自动产生一个隐含的析构函数
析构函数说明格式:~ <类名>();
- 注意事项:
- 函数名与类名相同,只是在前边加“~”符号;
- 析构函数不得返回任何值,没有返回类型;
- 析构函数不得带有任何参数;
- 析构函数只有在如下两种情况时才会被自动调用:
- 当对象定义在一个函数体中,该函数调用结束后,析构函数被自动调用。
- 用new为对象分配动态内存后,当使用delete释放对象时析构函数被自动调用。
- 如果没有定义任何析构函数,则编译器自动为类生成一个默认的析构函数。 如: ~person() { }
- 析构函数不能被重载;一个类只能有一个析构函数。
- 注意事项:
什么时候运行析构函数?
- 当对象的生命结束时,会自动执行它的析构函数。即当出现以下几种情况,析构函数就会被执行:
- 如果在函数中定义了一个对象,当函数调用结束时,释放对象前自动执行析构函数。
- static 局部对象在函数调用结束时,包含的对象不会被释放,只在main函数结束或调用exit函数时,才调用static局部对象的析构函数。
- 如果定义了一个全局对象,则在程序的流程离开其作用域时(如main函数结束,或exit语句),调用该全局对象的析构函数。
- 如果用new运算符动态地建立了一个对象,当用delete 运算符释放对象时,先调用该全局对象的析构函数。
- 当对象的生命结束时,会自动执行它的析构函数。即当出现以下几种情况,析构函数就会被执行:
调用构造函数和析构函数的顺序
- 撤消对象的顺序(在同一函数中):先构造的后析构,后构造的先析构。
#include <iostream> // 例
#include <string>
using namespace std;
class stud //声明类
{
public:
stud(int n,string nam,char s)
// 构造函数初始化私有成员变量
{
num=n;
name=nam;
sex=s;
cout<<"构造函数"<<endl;
}
~stud() // 析构函数在程序结束时自动调用
{
cout<<"销毁stud对象!!!"<<num<<endl;
}
void display()
{
cout<<"num="<<num<<endl;
cout<<"name="<<name<<endl;
cout<<"sex="<<sex<<endl;
}
private:
int num;
string name;
char sex;
}; // 类定义结束
int main() // ----- 主函数------
{
stud st1(10000,"Wang_li",'f');
st1.display();
stud st2(11111,"zhang_li",'t');
st2.display();
return 0;
}
注意:先构造的后析构,后构造的先析构,并非绝对成立!
对象不同的作用域,不同的存储类别,那么调用构造函数和析构函数的时候也有所不同。
例如:( 了 解 )
一个程序中有多个文件。在多个文件中定义了全局对象,那么这些对象的执行顺序是不确定的;
在函数中定义局部自动对象,如果函数被多次调用
如果函数中定义静态局部对象;那么函数调用结束时对象并不释放,只有main结束或调用exit中才调用析构函。.
构造函数和析构函数举例
#include <iostream>
using namespace std;
class Point
{
public:
Point(int xx,int yy);
~Point();
//...其他函数原型
private:
int x, y;
};
Point::Point(int xx,int yy)
{
x = xx;
y = yy;
}
Point::~Point()
{
}
//...其他函数的实现略