对象的初始化和清理也是两个非常重要的安全问题,一个对象或者变量没有初始时,对其使用后果是未知,同样的使用完一个变量,没有及时清理,也会造成一定的安全问题。C++ 为了给我们提供这种问题的解决方案,构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和对象清理工作。
创建一个对象,构造函数只会被调用一次,也就是说一旦构造函数被调用,说明产生了新对象
构造被调用多少次,程序结束时析构就会被调用多少次
- 构造函数作用在于创建对象时为对象的成员属性赋值,由编译器自动调用。
- 析构函数用于在对象内存释放之前,进行一些清理工作。
- 构造函数名字与类同名。
- 构造函数没有返回值,不能写 void。
示例
class Person
{
Person();
}
析构函数
- 析构函数不能有参数、不能有返回值,不能写 void。
语法:
~类名
示例
class Person
{
~Person();
}
构造函数分类
- 构造函数也支持函数重载,
- 按照功能可以分为: 普通构造和拷贝构造
- 按照参数个数可以分为有参构造和无参构造
- 普通构造函数,使用基本数据类型参数初始化对象。
- 拷贝构造函数,使用一个同类型的对象初始化本对象。
示例:
class Person
{
public:
Person()
{
mAge = 19;
mName = "wuyou";
cout<<"默认构造"<<endl;
}
Person(int age,string name)
{
mAge = age;
mName = name;
cout<<"有参构造"<<endl;
}
Person(const Person &p)
{
cout<<"拷贝构造"<<endl;
}
~Person()
{
}
public:
int mAge;
string mName;
}
匿名对象
- 匿名对象,匿名对象的生命周期只有当前行
- 匿名对象不能调用拷贝构造
class Person
{
public:
Person()
{
mAge = 19;
mName = "wuyou";
cout<<"默认构造"<<endl;
}
~Person(){}
public:
int mAge;
string mName;
}
void test()
{
//匿名对象,匿名对象的生命周期只有当前行
Person();
}
拷贝构造
- 默认的拷贝构造函数是逐字节拷贝
- 如果类内部包含对象成员,编译器会调用对象成员的构拷贝造函数
- 对于基础数据类型,还是逐字节拷贝
示例
class A
{
}
class B
{
public:
A a; //编译器调用A的拷贝构造
int b; //对于基础数据类型还是逐字节拷贝
}
void test()
{
B b1;
B b2(b1);
}
禁止使用拷贝
class Person
{
public:
Person();
Person(const Person &) = delete; //c11语法
private:
Person(const Person &){} //禁止使用拷贝构造
}
总结
- 类的内部一旦定义了构造函数,编译器不再提供默认构造函数 ,但是会提供拷贝构造函数
- 类内添加了自定义拷贝后,将不再提供默认构造