类默认生成的成员函数有六个:
构造函数、
拷贝构造函数、
析构函数、
赋值操作符重载、
取地址操作符重载
const修饰的取地址操作符重载
1.概念:初始化对象,有且仅在定义一个对象时自动执行一次的函数,就称为构造函数。
2.特性
a.函数名与类名相同。
b.无返回值。
c.实例化对象时系统会自动调用对应的构造函数。
d.构造函数可以重载。
e.构造函数可以在类内定义,也可以在类外定义。在类外定义时的格式:类名+“::”+函数名。
f.如果类定义中没有给出构造函数,则C++编译器会自动生成一个缺省的构造函数;如果我们定义了一个构造函数,系统就不会生成缺省的构造函数。
g.无参的构造函数和缺省的构造函数都认为是缺省的构造函数,所以缺省的构造函数只能有一个。
用日期类代码示例:
#include
using namespace std;
class Date
{
public:
Date() //构造函数
{}
Date(int year, int month, int day); //在类内声明一个构造函数,在类外定义
//在类内定义构造函数
//Date(int year, int month, int day) //构造函数重载
//{
// _year = year;
// _month = month;
// _day = day;
//}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
//在类外定义构造函数
Date::Date(int year = 2018, int month = 7, int day = 30) //构造函数重载{
_year = year;
_month = month;
_day = day;
}
3、构造函数的类型
a.无参构造函数和有参构造函数
当用户希望对不同的对象赋予不同的初始值时,就需要用到带参的构造函数,实现不同的初始化。因为用户不能调用构造函数,所以其对应的实参需要在定义对象的时候给定。
代码:
#include
using namespace std;
class Date
{
public:
//无参的构造函数
Date()
{}
//带参的构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date date1;//调用无参的构造函数
date1.Print();
Date date2(2020, 5, 30);//调用带参的构造函数
date2.Print();
system("pause");
return 0;
}
b.带缺省的构造函数
构造函数中参数的值既可以通过实参传递,也可以被指定为某些默认值。如果用户不指定实参值,编译系统就使用形参的默认值。
代码:
#include
using namespace std;
class Date
{
public:
//带缺省的构造函数
Date(int year = 2020, int month = 5, int day = 30)
{
_year = year;
_month = month;
_day = day;
}
//半缺省的构造函数(不常用)
Date(int year, int month = 7)
{
_year = year;
_month = month;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date date1;//调缺省的构造函数
date1.PrintfDate();
Date date2(2018, 7, 30);//调缺省的构造函数
date2.PrintfDate();
system("pause");
return 0;
}
c.用参数列表对数据成员初始化
C++还提供了一种初始化数据成员的方法——初始化列表。初始化列表位于构造函数参数列表之后,在函数体“{}”之前。该列表内的初始化工作发生在函数体内的任何代码被执行之前,所以最好用参数列表初始化。
代码:
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
初始化列表优点:
1)如果类存在继承关系,派生类可以直接在其初始化列表里调用基类的特定构造函数以向它传递参数,因为不能在初始化对象时访问基类的数据成员。
2)类的非静态const数据成员和引用成员只能在初始化列表里初始化,因为它们只存在初始化语义,而不存在赋值语义。
1.概念:创建对象时使用同类对象来进行初始化,这时所用的构造函数就是拷贝构造函数(Copy Constructor)。
拷贝构造函数也是构造函数,但它只有一个参数(同类的一个对象),传参采用对象的常引用形式。
拷贝构造函数的作用就是将实参对象的各成员值一一赋给新的对象中对应的成员。
2、拷贝构造函数的特征
a.拷贝构造函数其实是一个构造函数的重载。
b.拷贝构造函数的参数必须使用引用传参,使用传参方式会引发无穷递归调用。
c.若为显示定义,系统默认生成缺省的拷贝构造函数,缺省的拷贝构造函数会按照成员的声明顺序依次拷贝类成员进行初始化。
代码:
#include
using namespace std;
class Date
{
public:
//带缺省的构造函数
Date(int year = 2018, int month = 7, int day = 30)
{
_year = year;
_month = month;
_day = day;
}
//拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date date1;
date1.Print();
Date date2(date1);//调缺省的构造函数
date2.Print();
system("pause");
return 0;
}
对象可以直接访问私有成员变量的原因:
1)在类的成员函数里可以直接访问同类对象的私有或保护的成员。
2)C++的访问限定符是以类为单位的,即:在这个单位内的成员可以互相访问
1、析构函数概念
当一个对象的生命周期结束时,C++编译器会自动调用一个成员函数,这个成员函数即为析构函数,它的作用与构造函数相反。
2、析构函数的特征
1)无参数,无返回值,所以不能重载。其实,构造函数和析构函数都没有返回值
2)一个类有且只有一个析构函数,对象生命周期结束时,若未定义,C++编译系统会自动生成缺省的析构函数
3)因为函数压栈的关系,所以先构造的后析构,后构造的先析构。如果有全局对象或者静态局部对象,则它们在main函数结束或者调用exit函数时才被析构。
4)析构函数的作用并不是删除对象,而是在撤销对象时做一些清理工作,比如关闭打开的文件,释放开辟的动态内存等。
如果已经定义了两个或多个对象,则这些同类的对象之间可以相互赋值,即一个对象的值可以赋给另一个同类的对象。这里所指的对象的值是指对象中所有数据成员的值。对象之间的赋值是通过赋值运算符“=”重载实现的,即:将一个对象的值一一复制给另一对象的对应成员
代码:
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;
}
void PrintfDate()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};