构造函数和析构函数
概念:对象的初始化和清理是非常重要的,一个对象在使用之前,需要进行初始化,使用完成后也需要及时清理数据,简单来说构造函数时用来初始化成员属性的,析构函数时用来清理数据的。
C++中利用构造函数和析构函数解决以上的问题,这两个函数由编译器自动调用,完成对象的初始化和清理工作,对象的初始化和清理是强制性的,如果我们不提供构造函数和析构函数,编译器会给我们提供,但是是空实现。
构造函数
概念:主要作用于创建对象时为成员属性赋值,构造函数由编译器自动调用,无需手动调用。
语法:类名(){}
构造函数名和类名相同,无需返回值,构造函数默认是无参构造,也可以有参数,称为有参构造,本质是函数的重载,程序在调用对象的时候,会自动调用构造,无需手动调用,且只调用一次,因为只需要初始化一次。
构造函数分类
按函数参数分为默认构造和有参构造,按照类型分为普通构造和拷贝构造。
#include<iostream>
using namespace std;
class Person
{
public:Person()//默认(无参)构造函数{cout << "默认构造函数调用" << endl;}Person(int a)//有参构造{cout << "有参构造函数调用" << endl;}Person(const Person& p)//拷贝构造函数{cout << "拷贝构造函数调用" << endl;}~Person()//析构函数{cout << "析构函数调用" << endl;}
};
int main()
{Person p;
}
构造函数的调用
int main()
{//括号法调用Person p;//默认构造函数调用。需要注意的是调用默认构造函数不要在后面加括号,会被编译器认为是函数的声明。Person p2(10);//有参构造Person p3(p2);//拷贝构造函数调用,需要传入一个person类型的值//显示法调用Person p4 = Person(10);//有参构造,这里的Person(10)是匿名对象,当前行执行结束后,系统就会立即回收掉匿名对象Person p5 = Person(p4);//拷贝构造,需要注意不要用拷贝构造函数初始化匿名对象,例如Person(p4),编译器会认为是对象的声明//隐式转换法Person p6 = 10;//有参构造调用Person p7 = p6;//拷贝构造函数调用
}
拷贝构造函数的调用时机
1.使用一个创建完毕的对象来初始化一个新的对象
//使用一个创建完毕的对象来初始化一个新的对象
class Person
{
public:int m_age;Person()//默认构造{}Person(int age)//有参构造{m_age = age;}Person(const Person& p)//拷贝构造{m_age = p.m_age;}~Person()//析构{}};
int main()
{Person p1(10);Person p2(p1);cout << "p2的年龄" << p2.m_age << endl;//输出为10,说明以及成功拷贝过来了
}
2.值传递的方式给函数参数传值
void value(Person p)
{cout << p.m_age << endl;
}
int main()
{Person p(10);value(p);
}
3.值方式返回局部对象
Person value2()
{Person p1;cout << (int*)&p1 << endl;return p1;
}
void test()
{Person p = value2();cout << (int*)&p << endl;
}
int main()
{test();}
构造函数的调用规则
系统会默认提供三个函数给一个类中,默认构造,拷贝构造(对属性进行值拷贝),默认析构。
如果用户定义有参构造,系统不会再提供默认无参构造,但还是会提供拷贝构造,如果用户定义了拷贝构造函数,c++不会再提供其他的构造函数。
#include<iostream>
using namespace std;
class Person
{
public:int m_age;Person()//默认构造{cout << "默认构造函数调用" << endl;}Person(int age)//有参构造{m_age = age;cout << "有参构造函数调用" << endl;}Person(const Person& p)//拷贝构造{m_age = p.m_age;cout << "拷贝构造函数调用" << endl;}~Person()//析构{cout << "析构函数调用" << endl;}
};int main()
{Person p;//如果写了有参构造,没有写默认构造,系统也不会再提供默认构造了,再调用默认构造函数,编译器会报错p.m_age = 18;Person p2(p);//如果不写拷贝构造函数,系统会进行值拷贝,如果写了拷贝构造函数,编译器就不再提供默认构造。cout << "p2的年龄" << p2.m_age << endl;
}
析构函数
概念:主要作用在于在对象销毁前系统自动调用,完成清理工作。
语法:~类名(){}
析构函数和构造函数一样,没有返回值函数名前加~,且函数名与类名相同,区别是析构函数不能有参数,不能发生重载,也是会自动调用的。
#include<iostream>
using namespace std;
class Person
{
public:Person()//默认构造函数{cout << "默认构造函数调用" << endl;}~Person()//析构函数{cout << "析构函数调用" << endl;}
};
int main()
{Person p;//栈区数据,销毁前会自动调用析构函数
}
此时构造函数和析构函数没有手动调用,系统会自动调用。