如果变量在使用之前没有正确初始化或清除,将导致程序出错。(自我检讨一下,曾经因为没有对一个变量进行初始化就进行了使用,查了一晚上也没查出问题出在哪,后来发现后只想说,我是不是傻o(╥﹏╥)o )所以各位一定要切记对对象进行正确的初始化。
对对象进行初始化的一种方法是编写初始化函数,然而很多用户在解决问题时,常常忽视这些函数,以至于给程序带来了隐患。为了方便对象的初始化和清理工作,C++提供了两个特殊的成员函数:构造函数和析构函数。
构造函数的功能是在创建对象时,给数据成员赋初值,即对象的初始化。析构函数的功能是释放一个对象,在对象删除之前,用它来做一些内存释放等清理工作,它的功能与构造函数的功能正好相反。
构造函数是一种特殊的成员函数。它的特点为对象分配空间,进行初始化,并且在对象创建时会被系统自动执行。
定义构造函数原型的格式为:
类名(形参列表);
在类外定义构造函数的格式为:
类名::类名(形参列表)
{
//函数语句;
}
说明:
【例】构造函数应用举例:输出日期
#include
using namespace std;
class Data {
private:
int year, month, day;
public:
Data(int y, int m, int d);
void Print();
};
int main()
{
Data today(2019, 9, 10);
count << "today is ";
today.Print();
return 0;
}
Data::Data(int y, int m, int d)
{
year = y;
month = m;
day = d;
}
void Data::Print()
{
cout << year << "-" << month << "-" << day << endl;
}
说明:主函数main没有显示调用构造函数Data,构造函数是在创建对象today时,系统自动调用的。即在创建对象today时,系统自动调用构造函数today.Data,并将数据成语year、month、day初始化为2019、9和10。
class Fruit{
private:
int x,y;
public:
Fruit();
//......
};
Fruit::Fruit()
{
x=0;
y=0;
}
class Data{
private:
int year,month,day;
public:
Data(int y,int m,int d):year(y),month(m),day(d);
//构造函数初始化表对数据成员进行初始化
};
class Fruit{
private:
char name[20];
int num;
public:
Fruit(char name[ ],int n);
};
Fruit::Fruit(char na[ ],int n):num(n)
{
strcpy(name,na); //name是字符数组,所以用strcpy函数进行初始化
}
在对象生存期结束前,通常需要进行必要的清理工作。这些相关的清理工作由析构函数完成。析构函数也是一种特殊的成员函数,当删除对象时就会调用析构函数,也就是在对象的生存期即将结束时,由系统自动调用,随后这个对象也就消失了。注意,析构函数的目的是在系统回收对象内存前执行清理工作,以便内存可被重新用于保存新对象。
定义析构函数的一般格式:
~类名();
例如:
class Fruit{
public:
~Data();
};
特点:
说明:
【例】构造函数与析构函数的执行顺序 — Point类的多个对象的创建与释放。
#include
using namespace std;
class Point
{
public:
Point(int a,int b);
~Point();
private:
int x, y;
};
int main()
{
Point p1(1,2), p2(3,4);
return 0;
}
Point::Point(int a,int b) //定义构造函数
{
x = a;
y = b;
cout << "constructor......" << endl;
cout << "(" << x << "," << y << ")" << endl;
}
Point::~Point() //定义析构函数
{
cout << "destructor......" << endl;
cout << "(" << x << "," << y << ")" << endl;
}
运行结果
说明:调用构造函数的顺序与主函数main中创建对象的顺序一致,先创建对象p1,然后再创建对象p2;调用析构函数的顺序与创建对象的顺序相反,先析构对象p2,然后再析构对象p1。
①如果一个对象被定义在一个函数体内,则当这个函数结束时,该对象的析构函数会被自动调用。
#include
using namespace std;
class Point
{
public:
Point(int a,int b);
~Point();
private:
int x, y;
};
void fun(Point p);
int main()
{
cout << "inside main" << endl;
Point p1(1, 2);
fun(p1);
cout << "outside main" << endl;
return 0;
}
Point::Point(int a,int b)
{
x = a;
y = b;
cout << "constructor......" << endl;
}
Point::~Point()
{
cout << "destructor......" << endl;
}
void fun(Point p)
{
cout << "inside fun" << endl;
}
运行结果
说明:在主函数main中定义对象p1时,系统自动的调用p1的构造函数;当调用函数fun时,实参p1将值对应的赋给了形参p;当函数fun执行完,系统自动调用对象p的析构函数;当主函数main结束时,系统自动调用对象p1的析构函数。由此可见,只要对象超出它的作用域,系统就自动调用析构函数。
如果一个对象使用new运算符动态创建,在使用delet运算符释放它时,delet会自动调用析构函数(在程序中如果不显式撤销该对象,系统不会自动调用析构函数。也就是说new运算符动态创建的对象,如果不用delet运算符释放它,系统不会自动调用析构函数)详细用法将会在下节介绍到。