类和对象(中篇—类的6个默认成员函数)
上一篇博主讲了类和对象的基本概念以及定义一个类,最后实现了一个超级简单的Date类,这篇文章就基于上篇文章深入了解一下类的6个默认成员函数。
如果一个类中什么成员函数成员变量都没有,简称为空类。空类中什么都没有吗?并不是的,任何一个类在我们不写的情况下,都会自动生成下面6个默认成员函数。
一、构造函数(初始化)
C语言中对于一些数据结构的初始化我们要写一个Init函数并且调用它,这样会比较麻烦,所以C++中引入了构造函数来完成数据的初始化,构造函数会在实例化出对象的时候自动调用,比较方便,并且保证每个对象都会被初始化。
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。构造函数是特殊的成员函数,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主要任务并不是开空间创建对象,而是初始化对象。
构造函数的特性
1. 函数名与类名相同。
如Date类定义一个构造函数 Date() ,直接初始化为“2019-1-1”,可以这样写
Date()
{
_year = 2019;
_month = 1;
_day = 1;
}
2. 构造函数无返回值。
3. 在类实例化出对象的时候编译器会自动调用构造函数。
4. 构造函数可以重载。
如下:Date类的两个构造函数构成函数重载
Date()//无参调用
{
_year = 2019;
_month = 1;
_day = 1;
}
Date(int year, int month, int day)//传参调用
{
_year = year;
_month = month;
_day = day;
}
构造函数的使用如下:(注意:无参的构造函数不能带() )
Date d1;//无参的构造函数不能带()
d1.Print();
Date d2(2019, 2, 2);
d2.Print();
5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
还是基于上面的Date类,如果我们将构造函数屏蔽掉,那么无参的构造函数Date d1;是可以编译运行通过的。这就说明我们没有写,编译器也会自动生成,如果我们写了构造函数的话编译器就会调用我们写的构造函数。
class Date
{
public:
/*
// 如果用户显式定义了构造函数,编译器将不再生成
Date (int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
*/
private:
int _year;
int _month;
int _day;
};
void Test()
{
// 没有定义构造函数,对象也可以创建成功
//因此此处调用的是编译器生成的默认构造函数
Date d;
}
6.默认构造函数就是指不用传参也可以初始化对象的函数,在C++中具体有3种----编译器自动生成的默认构造函数、无参的默认构造函数、全缺省的默认构造函数。但是默认构造函数只能存在一个。
例如下方的代码会与歧义:
Date()
{
_year = 2019 ;
_month = 1 ;
_day = 1;
}
Date (int year = 2019, int month = 2, int day = 2)
{
_year = year;
_month = month;
_day = day;
}
这两个默认构造函数分别是无参的默认构造函数、全缺省的默认构造函数,但是当我们在实例化调用Date d1;时,就会产生歧义,到底是调用无参的默认构造函数初始化为2019-1-1呢?还是调用全缺省的默认构造函数初始化为2019-2-2呢?
所以说呀!默认构造函数只能存在一个!但是我们推荐全缺省的默认构造函数,因为全缺省的默认构造函数就可以涵盖无参的默认构造函数,就是可以无参调用,也可以传参调用,就会比较全面一点。
7.对于编译器自动生成的默认构造函数我们又看不到它,那它到底都干了什么事情呢?原来编译器把类型分成了内置类型和自定义类型,内置类型就是已经定义好的类型,比如int,char等。自定义类型就是我们自己定义的,比如下面的Time。
接下来看这么一段代码我们就知道编译器自动生成的默认构造函数都干了那些事情。
class Time//Time类
{
public:
Time()
{
std::cout << "Time()" << std::endl;
_hour = 0;
_minute = 0;
_second = 0;
}
private:
int _hour;
int _minute;
int _second;
};
class Date//Date类
{
private:
//内置类型
int _year;
int _month;
int _day;
//自定义类型
Time _t;
};
int main()
{
Date d1;
system("pause");
return 0;
}
这里我们写了Date类,Date类里面有内置类型和自定义类型,我们没有写Date类的构造函数,因此在实例化d1时,编译器会自动生成一个默认构造函数来初始化Date类里的成员变量。对于Time自定义类型我们写了它的构造函数。运行结果如下:
说明这里调用了Time类的默认构造函数。因此我们知道了如果我们没有写构造函数,编译器会自动生成一个默认构造函数,这个默认构造函数对内置类型好像没有干什么,但是它对自定义类型就会比较严格了,就会去调用自定义类型的构造函数来完成初始化。