构造函数与析构函数
意义:
构造函数:对对象中的属性进行初始化设置
析构函数:在对象销毁前,对相应的对象资源进行回收
注意:
- 构造与析构函数都是编译器要求必须要存在的函数,每一个对象的定义和销毁都会伴随构造和析构调用。
- 编译器会自动调用构造和析构函数,无需手动调用。
- 在没有编写任何构造与析构函数时,编译器会自动提供,但是提供的都是空实现。
构造函数的编写
语法:
- 没有返回值(void也不用写)
- 函数名固定,与类名相同
- 可以有参数,可以重载
- 自动调用,一个对象只调用一次
class person
{
public:
person()
{
cout<<"构造函数"<<endl;
}
}
析构函数的编写
- 没有返回值(void也不写)
- 函数名固定,与类名相同,有~在名字前
- 没有参数,不能重载
- 销毁前自动调用每一个对象只调用一次
class person
{
public:
person()
{
cout<<"构造函数"<<ecdl;
}
~person()
{
cout<<"析构函数"<<endl;
}
}
构造函数的分类与调用
- 构造分类
无参构造
person p1;//直接调用无参构造函数
person p1=Person();//赋值方式调用无参构造
带参构造
person p1("yy",12);//直接调用带参构造
person p1=23;//隐式调用带参构造
拷贝构造
person p3(p1);//调用拷贝构造
- 拷贝构造的调用时机
1. 在利用一个对象初始化另一个对象时
person p3(p1);
person p3=p1;
2. 在函数以值传递对象参数时
void myfun(person p1)
{
}
int main()
{
person p2("vbh");
myfun(p2);//person p1=p2;
}
3. 当函数返回一个局部对象时
person myfun()
{
person p1("yy");
return p1;
}
int main()
{
person ret_p=myfun();//调用拷贝构造
}
- 深浅拷贝问题
浅拷贝:直接对两个对象的属性进行赋值操作,指针也是直接赋值。(导致两个指针指向同一个空间)当析构时,会出现多次释放同一个空间的问题。
深拷贝:对于堆空间数据进行重新开辟对空间操作,然后赋值。(两个指针对应两个对空间)不会引起空间多次释放。
class person
{
public:
int *m_age;
}
person p1;
//int a=19;
//p1.m_age=&a;
p1.m_age=new int(39);
//浅拷贝:m_age=p1.m_age;
//深拷贝:m_age=new int(*p1.m_age)
如果成员属性中有堆开辟的空间,就自己编写拷贝构造函数防止浅拷贝带来的问题
参数初始化列表
- 作用:替换代码内部赋值,简化代码
- 语法:构造函数(参数1、参数二……):属性1(参数1),属性2(参数2)
person(int a,int b):m_a(a),m_b(b)//参数与属性对应,顺序可以不按照参数顺序
组合思想——当一个对象作为类成员
构造与析构的顺序:先构造类对象成员,再构造自身,先析构自身,后析构类对象成员(栈:先进后出)
class weapon
{
public:
int att;
string kind;
}
class hero
{
public:
weapon h_w1;
string h_name;
}
int main()
{
hero h1;
return 0;
}