构造函数
类中定义了成员函数,但是在调用前忘记初始化成员函数,此时程序会出错。为了解决数据成员自动初始化的问题,此时就用到了构造函数。
- 构造函数是类的一种特殊成员,本质上也是类的成员函数。
- 函数名和类名相同,没有返回类型,可以有参数,也可以没有参数。
- 当创建类的一个新对象时,构造函数被自动调用,完成对象的初始化工作。
那么构造函数如何定义和使用?
定义构造函数
例:
class Clock
{
private:
int Hour,Minute,Second;
public:
Clock(int h,int m,int s);
......
};
该类比前面例子(类的实现)中多出的公共成员函数Clock(int h,int m,int s);
即为构造函数。
实现构造函数:初始化数据成员
- 赋值语句方式
Clock(int h,int m,int s)
{
Hour=h;
Minute=m;
Second=s;
}//在函数内部使用参数初始化数据成员
- 表达式表方式
Clock(int h,int m,int s):Hour(h),Minute(m),Second(s){}
调用方式
Clock clock_1(3,20,20);
如果构造函数参数只有一个时,可以用赋值"="方式初始化
Clock(int n):Hour(n);//定义
......
Clock clock_1(8);//调用
Clock clock_2=8;//调用
重载构造函数
- 一个类可以提供多个构造函数,即构造函数的重载。
- 重载的目的是为了满足不同的初始化需要。
class Clock
{
private:
int Hour,Minute;
public:
Clock(int h,int m,int s)
Clock();
Clock(char *timestr);
};
调用时函数参数不同调用的构造函数也不同
void main()
{
Clock clock(3,20,20)
Clock clock();
Clock clock("15:20:20");
};
具有缺省参数的构造函数
- 构造函数也可以有缺省参数。如果在类外实现该函数时,就不能再说明缺省值了。
class Clock
{
private:
int Hour,Minute;
public:
Clock(int h=0,int m=0,int s=0);//如果参数为0则都可以缺省
Clock(char *timestr);
};//该类不能再有Clock()构造函数,如果再有Clock()调用时程序则不知道该调用哪一个函数
缺省的构造函数
- 对于没有构造函数的类,编译器将会自动为它生成一个没有参数的构造函数,该函数不做任何工作。
- 如果自己写构造函数,则这个缺省的构造函数会消失。
析构函数
使用过类之后我们要做一些释放类收尾工作,但是有时候会忘记收尾,这时又会出错。为了解决“金鱼的记忆”这个老毛病,C++很贴心的提供了析构函数。
- 专门用于处理对象销毁时候的清理工作。
- 析构函数没有返回类型,没有参数,函数名是在类名前加"~"。
- 析构函数会在对象的生存期结束后被自动调用。
- 如果没有写析构函数,编译器会生成一个不做任何事的缺省的析构函数。
析构函数的定义与实现
class Clock
{
private:
int Hour,Minute,Second;
public:
Clock(int h,int m,int s);
~Clock(){cout<<"Clock obj destroyed!"<<endl;}
......
};
//析构函数也可以在类外实现
Clock::~Clock(){cout<<"Clock obj destroyed!"<<endl;}
需要注意的问题
析构函数和动态内存管理一起使用容易出错
- 删除动态内存失败。
- 读写已删除的对象。
- 对同一个内存空间使用两次delete。
- 有两个及以上的指针指向同一个动态内存分配的对象
- 一个指针,多次删除
拷贝构造函数
多次初始化很麻烦,我们可以使用已经存在的类对象构造一个一模一样的新类对象。
- 如果将与自己同类的对象的引用作为参数进行构造函数时的初始化时,该构造函数就称为拷贝构造函数。
- 拷贝构造函数的特点:
- 拷贝构造函数也是构造函数,所以当创建类对象时系统会自动创建
- 拷贝构造函数将一个已经创建好的对象作为参数,根据需要将该对象中的数据成员逐一对应赋值给新对象。
拷贝构造函数的定义与实现
class Clock
{
private:
int Hour,Minute,Second;
public:
Clock(int h,int m,int s){Hour=h;Minute=m;Second=s;}//普通构造函数
Clock(Clock &obj)
{
Hour=obj.Hour;
Minute=obj.Minute;
Second=obj.Second;
}//该函数即为拷贝构造函数
}
void main()
{
Clock obj1(3,20,20);//调用Clock(int h,int m,int s)
Clock obj2(obj1);//调用Clock(Clock &obj)
Clock obj3=obj2;//创建时直接用obj2初始化,同样调用Clock(Clock &obj)
}
缺省的拷贝构造函数
- 如果没有定义拷贝构造函数,那么编译器会为类对象创建一个缺省的拷贝构造函数。
- 缺省的拷贝构造函数使用位拷贝的方法来完成对象到对象的复制。
如果上面的代码里没有定义拷贝构造函数,那么Clock obj2(obj1)
和Clock obj3=obj2
同样能完成拷贝,并且是精确拷贝。
- 拷贝构造函数在使用时也要注意释放空间时重复释放的问题。
拷贝构造函数还能再哪里用
除了在创建新对象时可以使用拷贝构造函数,还可以在以下情况使用
- 对象作为函数参数
- 函数返回对象