1)构造函数:
初始化对象,有且仅在定义一个对象时自动执行一次的函数
类的数据成员是不能在声明类的时候初始化的,因为类并不是一个实体,而是一种抽象的数据类型,并不占据存储空间
构造函数的特性:
1、函数名与类名相同
2、无返回值
3、实例化对象时系统会自动调用对应的构造函数
4、可重载
5、构造函数可以在类内定义,可以在类外定义
6、如果类定义中没有给出构造函数,则C++编译器会自动生成一个缺省的构造函数;如果我们定义了一个构造函数,系统就不会生成缺省的构造函数。
7、无参的构造函数和缺省的构造函数都认为是缺省的构造函数,所以缺省的构造函数只能有一个。
8、不用传参的构造函数是默认构造函数
构造函数的类型:
1、无参构造函数和有参构造函数
当用户希望对不同的对象赋予不同的初始值时,就需要用到带参的构造函数,实现不同的初始化。因为用户不能调用构造函数,所以其对应的实参需要在定义对象的时候给定。
2、带缺省的构造函数
构造函数中参数的值既可以通过实参传递,也可以被指定为某些默认值。如果用户不指定实参值,编译系统就使用形参的默认值。
用参数列表对数据成员初始化:
1初始化列表,位于构造函数参数列表之后,在函数体“{}”之前。该列表内的初始化工作发生在函数体内的任何代码被执行之前。
初始化列表优点:
1.如果类存在继承关系,派生类可以直接在其初始化列表里调用基类的特定构造函数以向它传递参数,因为不能在初始化对象时访问基类的数据成员。
2.类的非静态const数据成员和引用成员只能在初始化列表里初始化,因为它们只存在初始化语义,而不存在赋值语义。
3.类的数据成员的初始化可以采用初始化列表或函数体内赋值两种方式,但是使用初始化列表的方式效率更高。
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
class Date
{
public:
Date() //构造函数 (无参构造函数)
{}
Date(int year, int month, int day); //在类内声明一个构造函数,在类外定义
//在类内定义构造函数
Date(int year, int month, int day) //构造函数重载 (带参构造函数)
{
_year = year;
_month = month;
_day = day;
}
//带缺省的构造函数
Date(int year = 2018, int month = 7, int day = 30)
{
_year = year;
_month = month;
_day = day;
}
//半缺省的构造函数(不常用)
Date(int year, int month = 7)
{
_year = year;
_month = month;
}
void PrintfDate()
{
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;
}
int main()
{
Date date1;//调用无参构造函数
date1.PrintfDate(); //因为无参的构造函数没有初始化,所以打印出来是随机值。
Date date2(2018,7,30); //调用带参构造函数
date1.PrintfDate();
/*Date date3(); //注意:这样调用无参的构造函数是错的
date3.PrintfDate();*/
return 0;
}
2)拷贝构造函数:
1、创建对象时使用同类对象进行处初始化所用的构造函数
2、只有一个参数,这个参数只能是本类的一个对象,且采用对象的常引用形式
拷贝构造函数的特性:
1、是构造函数的重载
2、参数必须使用引用传参,使用传值方式会引发无穷递归调用。
3、若未显示定义,系统默认生成缺省拷贝构造函数,缺省的拷贝构造函数会按照成员的声明顺序依次拷贝类成员进行初始 化。
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 PrintfDate()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date date1;
date1.PrintfDate();
//下面调用的两种方法都是拷贝构造函数,是等价的
Date date2(date1);//调缺省的构造函数
date2.PrintfDate();
Date date3 = date1;
date3.PrintfDate();
system("pause");
return 0;
}
3)析构函数:
当一个对象的生命周期结束时,C++编译器会自动调用一个成员函数,这个成员函数即为析构函数,作用与构造函数相反。
析构函数的特性:
1、类名前加”~“字符
2、无参,无返回值,不能重载
3、一个类有且只有一个析构函数,对象生命周期结束时,若未定义,C++编译系统会自动生成缺省的析构函数。
4、调用构造函数和析构函数的顺序 :因为函数压栈的关系,所以先构造的后析构,后构造的先析构。如果有全局对象或者静态局部对象,则它们在main函数结束或者调用exit函数时才被析构。
5、析构函数的作用并不是删除对象,而是在撤销对象时做一些清理工作,比如关闭打开的文件,释放开辟的动态内存等。
class Array
{
public:
Array(int size)
{
_ptr = (int*)malloc(size*sizeof(int));
}
//这里的析构函数需要完成清理工作
~Array()
{
if (_ptr)
{
free(_ptr);//释放堆上内存
_ptr = NULL;//将指针置空
}
}
private:
int* _ptr;
};
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;
};
5)取地址操作符重载
class Date
{
public :
Date* operator &()
{
return this ;
}
const Date * operator&() const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
6)const修饰的取地址运算符重载
在成员函数后面加const,const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数内不会被改变。
class Date
{
public :
void Display ()
{
cout<<"Display ()" <<endl;
cout<<"year:" <<_year<< endl;
cout<<"month:" <<_month<< endl;
cout<<"day:" <<_day<< endl<<endl ;
}
void Display () const //const成员函数
{
cout<<"Display () const" <<endl;
cout<<"year:" <<_year<< endl;
cout<<"month:" <<_month<< endl;
cout<<"day:" <<_day<< endl<<endl;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
void Test ()
{
Date d1 ;
d1.Display ();
const Date d2;
d2.Display ();
}