构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次
特性
- 构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象
- 函数名和类名相同
- 没有返回值
- 对象实例化时编译器自动调用对应的构造函数
- 构造函数可以重载
也就是说,构造函数主要是为了给对象进行初始化,并且可以自动调用。构造函数可以重载,说明类里面可以有多个构造函数,下面以日期类举例
class Date
{
public:
//无参的构造函数
Date()
{
_year = 2022;
_month = 9;
_day = 27;
}
//有参的构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(2022, 9, 28);
return 0;
}
可以看到,上面创建的d1和d2对象都被初始化了,这是因为我们在类里面写了构造函数,如果我们没有去创建并调用初始化函数,构造函数就会自动调用。d1我们在创建的时候并没有传参,所以它就默认使用无参的构造函数;d2我们给它传了参数所以它就调用了有参的构造函数,当然构造函数我们也可以使用缺省参数。
下面再来看一种情况
class Date
{
public:
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
return 0;
}
上面的代码,我们没有去定义构造函数,那么这时可以看到d1还是会被创建,只是值是随机的。在C++编译器中,如果我们没有去定义构造函数,那么它会自动帮我们生成一个无参的默认构造函数,如果我们去定义了构造函数则编译器将不会生成
那么问题来了,这个默认的构造函数究竟有什么用呢?
事实上,C++把类型分成了内置类型和外置类型两种。内置类型就是语言本身提供的数据类型,例如:int char double…这些都是内置类型;而外置类型就是我们使用class/struct/union这些去自定义的类型。那么在编译器生成的默认构造函数就会让自定义类型去调用其本身的默认成员函数,看下面代码
class Time
{
public:
Time()
{
_hour = 10;
_min = 10;
_sec = 10;
}
private:
int _hour;
int _min;
int _sec;
};
class Date
{
public:
private:
int _year;
int _month;
int _day;
Time _t;
};
int main()
{
Date d1;
return 0;
}
可以看到,d1里面的Time类型的外置类型就会去调用它这个类型的构造函数,从而实现它的初始化。也就是说,类里面的默认构造函数是不会对外置类型起作用的,外置类型需要自己去其类里面调用其构造函数
那么问题又来了,如果我们忘记了去定义构造函数,那变量就是随机值这样就不太好,那么能不能够在声明内置类型变量的时候就给它赋初始值呢?答案是:可以的,在C++11中就针对内置类型成员不初始化的缺陷进行补丁,即:内置类型成员变量在类中声明时可以给默认值
class Time
{
public:
Time()
{
_hour = 10;
_min = 10;
_sec = 10;
}
private:
int _hour;
int _min;
int _sec;
};
class Date
{
public:
private:
int _year = 2022;
int _month = 9;
int _day = 27;
Time _t;
};
int main()
{
Date d1;
return 0;
}
可以看到,赋了初值之后,如果我们不去定义构造函数,那么内置类型变量就会是初始值。
构造函数还需注意:无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数
析构函数
与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。就比如我们实现栈,需要开辟空间,在我们使用完之后要对空间进行销毁防止内存泄漏,那么析构函数就可以帮助我们自动销毁内存,防止我们忘记了操作
特性
- 析构函数名是在类名前加上字符 ~
- 无参数无返回值类型
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
- 对象生命周期结束时,C++编译系统系统自动调用析构函数
class Stack
{
public:
Stack(int capacity = 4)
{
_a = (int*)malloc(sizeof(int) * capacity);
if (_a == nullptr)
return;
_capacity = capacity;
_size = 0;
}
void Push(int data)
{
_a[_size++] = data;
}
~Stack()
{
free(_a);
_a = nullptr;
_capacity = 0;
_size = 0;
}
private:
int* _a;
int _size