首先我们先来大致了解类中的6个默认成员函数
当一个类中任何成员都没有的时候,我们就简称其为空类,但是我们要知道的是,空类当中也并不是什么都没有,任何一个类,在我们不去写的情况下,都会自动生成下面的6个默认成员函数。这就是类中的6个默认成员函数。
这6个默认成员函数可以分为以下三类:
接下来我们先来看其中的构造函数和析构函数
构造函数
先来看一个日期类:
#include
using namespace std;
class Date
{
int m_year;
int m_month;
int m_day;
public:
void SetDate(int year, int month, int day)
{
m_year = year;
m_month = month;
m_day = day;
}
void Display()
{
cout << m_year << '-' << m_month << '-' << m_day << endl;
}
};
int main()
{
Date d1, d2;
d1.SetDate(2019, 12, 1);
d1.Display();
d2.SetDate(2019, 10, 1);
d2.Display();
system("pause");
return 0;
}
在这个Date类当中,我们可以通过SetDate这个公有的成员函数来给对象设置内容,但是如果每创建一次对象,都调用这个函数去设置信息,会显得有些麻烦,所以就考虑能不能在创建对象的时候,就将信息设置进去!
这就要用到构造函数了,构造函数其实是一个特殊的成员函数,它的名字与类名相同,在创建类类型的对象时由编译器自动调用,这样保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只会调用一次!
需要注意的是构造函数的名字叫做构造,但它的任务并不是开辟空间创建对象,而是初始化对象。
构造函数的特征
比如把我们上面的日期类改为下面这样:
#include
using namespace std;
class Date
{
int m_year;
int m_month;
int m_day;
public:
//无参构造函数
Date()
{
}
//带参构造函数
Date(int year, int month, int day)
{
m_year = year;
m_month = month;
m_day = day;
}
void Display()
{
cout << m_year << '-' << m_month << '-' << m_day << endl;
}
};
int main()
{
Date d1; //调用无参构造
Date d2(2019, 1, 1); //调用带参的构造函数
//注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,不然就变成了函数声明
//比如下面这样,声明了d3函数,这个函数没有参数,返回值是个Date类型的对象。
Date d3();
system("pause");
return 0;
}
如果我们在类中没有显示定义构造函数那么我们的C++编译器会自动生成一个无参的默认构造函数,而当我们自己显式定义之后,编译器将不再生成。比如下面这样:
class Date
{
int m_year;
int m_month;
int m_day;
};
void Test()
{
Date d;
}
像这样没有定义构造函数,对象也是可以创建成功的,因为这里调用的是编译器生成的默认构造函数
无参的构造函数和全部缺省的构造函数都称为默认构造函数,并且一定要注意默认构造函数只能有一个
无参构造函数,全缺省构造函数,我们不去定义而编译器自己生成的构造函数,都可以认为是默认构造函数。
可以试试下面这段代码能否通过编译
#include
using namespace std;
class Date
{
int m_year;
int m_month;
int m_day;
public:
Date()
{
m_year = 2019;
m_month = 12;
m_year = 1;
}
//带参构造函数
Date(int year = 2008, int month = 8, int day = 8)
{
m_year = year;
m_month = month;
m_day = day;
}
};
int main()
{
Date d1;
system("pause");
return 0;
}
析构函数
通过构造函数的学习,我们知道一个对象是怎么来的,那么一个对象又是怎么没的呢?
析构函数与构造函数功能相反,析构函数并不是完成对对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁的时候会自动调用析构函数,完成类的一些资源清理工作。
析构函数也是特殊的成员函数
析构函数的特征
看下面这段代码,了解一下析构函数的使用:
typedef int DataType;
class SeqList
{
int * m_data;
size_t m_size;
size_t m_capacity;
public:
SeqList(int capacity = 10)
{
m_data = (DataType *)malloc(capacity * sizeof(DataType));
assert(m_data);
m_size = 0;
m_capacity = capacity;
}
~SeqList()
{
if (m_data)
{
free(m_data); //释放堆上空间
m_data = NULL; //将指针置为NULL,防止变为野指针
m_capacity = 0;
m_size = 0;
}
}
};
构造函数总结
析构函数总结
关于浅拷贝和深拷贝
浅拷贝: 直接复制内存
深拷贝: 当内存成员中有指向堆的指针,就必须重新给该指针分配空间,然后将目标对象指针所指空间的内容拷贝到新分配的空间.(如果不这样做,会导致两个指针指向同一片空间,从而在析构中多次释放).