隐含的this指针
1.每个成员函数都有一个指针形参,它的名字是固定的,称为this指针,this指针是隐式的。
2.编译器会对成员函数进行处理,在对象调用成员函数的时候,对象地址作为实参传递给成员函数的第一个形参this指针。
3.this指针是成员函数隐含指针形参,是编译器自己处理的,我们不能在成员函数的形参中添加this的参数定义,也不能在调用时,显示传递对象的地址给this指针。
类的默认成员函数
我们定义一个日期类作为例子
class Date
{
public:
void Display()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
日期的成员变量是私有的,我们怎么初始化这些私有的成员变量?
1.构造函数
成员变量为私有的,要对他们进行初始化,必须用一个共有函数来进行,同时这个函数应该有且仅在定义对象时自动执行一次,这时调用的函数称为构造函数。
构造函数是特殊的成员函数,它的特征:
1.函数名与类名相同。
2.无返回值。
3.对象构造时系统自动调用对应的构造函数。
4.构造函数可以重载。
5.构造函数可以在类中定义,也可以在类外定义。
6.如果类定义中没有给出析构函数,则C++编译器自动产生一个缺省的构造函数,但只要我们定义了一个构造函数,系统就不会自动生成缺省的构造函数。
7.无参的构造函数和全缺省的构造函数,都认为是缺省构造函数,并且缺省构造函数只能有一个
无参构造函数&带参构造函数
class Date
{
public:
//1.无参构造函数
Date()
{}
//2.带参构造函数
Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date d1;
Date d2(2015,1,1);
}
带缺省参数的构造函数
Date(int year = 2000,int month = 1;int day = 1)
{
-year = year;
_month = month;
_day = day;
}
拷贝构造函数
创建对象时使用同类对象来进行初始化,这时所用的构造函数称为拷贝构造函数,拷贝构造函数是特殊的构造函数。
特征:
1.拷贝构造函数其实是构造函数的重载。
2.拷贝构造函数的形参必须使用引用传参,使用传值方式会引起无限递归调用。
3.若未显示定义,系统会默认缺省的拷贝构造函数。缺省的拷贝构造函数会依次拷贝类成员进行初始化、
class Date
{
public:
Date()
{}
//拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}//在这里我们对象可以直接访问私有的成员变量
//1.在类的成员函数中可以直接访问同类对象的私有/保护成员
//2.C++的访问限定符是以类为单位的,也就是说在这个单位内的成员可以互相访问。
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date d1;
//下面两种用法都是调用拷贝构造函数,是等价的。
Date d2(d1);
Date d3 = d1;
}
析构函数
当一个对象的生命周期结束时,C++编译系统会自动调用一个成员函数,这个特殊的成员函数就是析构函数。
析构函数是特殊的成员函数特征如下:
1.析构函数在类名上加字符~。
2.析构函数无参数返回值。
3.一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。
4.对象生命周期结束时,C++编译系统自动调用析构函数。
5.注意析构函数体内并不是删除对象,而是做了一些清理工作。
赋值运算符重载
拷贝构造函数是创建的对象,使用一个已有对象来初始化这个准备创建的对象。
赋值运算符的重载是对一个已经存在的对象进行拷贝赋值
class Date
{
public:
Date()
{}
//拷贝构造函数
Date(const Date& d)
:_year(d._year)
,_month(d._month)
,_day(d._day)
{}
//赋值操作符的重载
Date& operator=(const Date& d)
{
if(this != &d)//判断是不是本身
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
}
return *this;
//我们的this 被赋值了,而且出了函数还存在,那么就要拿Date类型来接收参数
}
private:
int _year;
int _month;
int _day;
};
void Test()
{
Date d1;
Date d2 = d1;//调用拷贝函数
Date d3;
d3 = d1;//调用赋值运算符的重载
}
深入探索构造函数
类的成员变量有两种初始化方式:
1.初始化列表。
2.构造函数体内进行复制。
初始化列表以一个冒号开始,接着一个都要分隔数据列表,每个数据成员都放在一个括号中进行初始化。尽量使用初始化列表进行初始化,因为它更高效。
哪些成员变量必须放在初始化列表里面?
1.常量成员变量。
2.引用类型成员变量。
3.没有缺省构造函数的类成员变量。
成员变量按声明顺序依次初始化,而费初始化列表出现的顺序