文章目录
一、构造函数
1、构造函数的功能
构造函数是一个类的成员函数,在类创建好后(就是开劈好空间)自动调用构造函数对类的成员变量进行初始化。
2、构造函数的创建
构造函数的名字跟它所在的类的名字一样,构造函数没有返回值(viod 也不用写),构造函数支持重载,就是根据传参来区分调用哪一个构造函数。
#include <iostream>
class Date
{
public:
//不传参的构造函数
Date()
{
_year = 2020;
_month = 1;
_day = 1;
}
//传参
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(2024, 8, 12);
return 0;
}
在不传参时调用构造函数不用加括号。
//Date d1();
//如果没有参数调用时加括号有歧义
//可能是一个函数申明
//返回类型为Date,无参的名为d1的函数声明
3、默认构造函数
- 当我们没有显示写构造函数时,系统自动生成一个默认构造函数来初始化成员变量。
我们写了构造编译器就不会生成默认构造。
编译器自动生成的构造函数对内置类型有可能不做处理,对自定义类型会调用对应的构造函数
内置类型是int/char/double/指针等类型,自定义类型是class/struct关键字创建的类型
所以构造函数往往需要自己写
默认构造有三个:
- 我们不写构造编译器默认生成的构造
- 无参的默认构造
- 全缺省构造在调用时不传参
总结就是不传实参就调用的构造叫默认构造
无参和全缺省的构造不能同时存在,它们虽然构成重载,但在不穿任何参数时调用会产生歧义
没有默认构造存在编译器会报错
二、析构函数
1、析构函数的功能
析构完成类对象的销毁,在声明周期结束时会自动销毁,一般对栈帧上的空间就是释放,对没有使用资源的我们不用管,系统自动生成的析构就够了,使用资源的就需要自己显示写析构,资源就是malloc或fopen申请的空间。
2、析构函数的的创建
析构函数的名字是类的名字前加一个~,是跟构造函数相反,也不用加返回值(void 也不用加),不用重载,一个类有一个析构就可以了,在声明周期结束时会自动调用。
没有写析构编译器会自动生成一个默认析构,对内置类型不做处理,对自定义类型会自动调用对应的析构。
#include <iostream>
class stack
{
public:
stack(int n = 4)
{
_a = (stackDataType*)malloc(n * sizeof(stackDataType));
if (_a == NULL)
{
perror("satck :: malloc fail");
exit(1);
}
_capacity = n;
_top = 0;
}
//析构
~stack()
{
free(_a);
_a = nullptr;
_capacity = _top = 0;
}
private:
typedef int stackDataType;
stackDataType* _a;
int _capacity;
int _top;
};
int main()
{
stack s;
return 0;
}
⼀个局部域的多个对象,C++规定后定义的先析构。
在类里创建了析构,但编译器也会去调用自定义类型对应的析构。
#include <iostream>
class stack
{
public:
stack(int n = 4)
{
_a = (stackDataType*)malloc(n * sizeof(stackDataType));
if (_a == NULL)
{
perror("satck :: malloc fail");
exit(1);
}
_capacity = n;
_top = 0;
}
//析构
~stack()
{
free(_a);
_a = nullptr;
_capacity = _top = 0;
std::cout << "~stack()" << std::endl;
}
private:
typedef int stackDataType;
stackDataType* _a;
int _capacity;
int _top;
};
class MyQueue
{
public:
~MyQueue()
{
std::cout << "~MyQueue()" << std::endl;
}
private:
stack p1;
stack p2;
};
int main()
{
MyQueue q;
return 0;
}
给MyQueue写了析构,但还是调用了两次~stack(),所以对于自定义类型无论如何都会调用它对应的析构。
三、拷贝构造函数
1、拷贝构造的功能
拷贝构造函数是特殊的构造函数,在类的对象初始化时自动调用拷贝构造函数将类已经实例化后对象的值拷贝给新创建的对象。在函数调用时,函数形参的类型是类时也会先调用拷贝构造。
拷贝构造函数跟析构函数一样,往往时类有指向资源时,需要自己写拷贝构造。
如果指向的资源了·不自己写拷贝构造,而系统自动生成的拷贝构造是浅拷贝,多个类对象指向同一块空间,不是期望的结果。
2、拷贝构造的创建
- 拷贝构造函是构造函数的一个重载,形参的类型就是类的引用。
在C++中传值传参时都会自动调用拷贝构造函数,如果不引用传参就会不停递归拷贝构造函数,形参死归。
上面图片的拷贝构造写的有问题,在函数调用类做返回值时调用拷贝构造会产生权限放大的错误,所以可以用const修饰更安全
3、深拷贝
对于占用资源的类对象进行拷贝时就要自己写拷贝构造完成的目的就是深拷贝。
就像栈这样的数据结构要进行拷贝时,确保两个对象不指向同一块空间。