目录
类的六个默认函数
- 构造函数
- 拷贝构造函数
- 析构函数
- 赋值操作符重载
- 取地址操作符重载
- const修饰的取地址操作
构造函数:
构造函数是一个对着对象创建而被自动调用的公有成员函数,有且仅在定义对象时自动执行一次,它的作用主要是为对象左初始化。
构造函数是特殊的成员函数,特征如下:
1:函数名与类名相同
2:无返回值
3:对象构造(对象实例化)是系统自动调用对应的构造函数
4:构造函数可以重载
5:构造函数可以在类中定义,也可以在类外定义
6:如果类中的没有给出构造函数,编译器会自动产生一个默认的构造函数,但只要我们定义了构造函数,系统就不会自动产生默认的构造函数
7:无参的构造函数和全默认值的构造函数都认为是默认构造函数,并且默认的构造函数只能有一个
无参的构造函数和带参的构造函数:
class Date
{
public:
//无参的构造函数
Date()
{ }
//带参的构造函数
Date(int year,int month,int day);
{
_year = year;
_moth = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date date1;//调用无参的构造函数
Date date2(2018, 9, 5);//调用带参的构造函数
}
调用默认构造函数:
class Date
{
public:
//默认参数的构造函数
Date(int year = 2018,int month = 9,int day = 4);
{
_year = year;
_moth = month;
_day = day;
}
//半默认参数的构造函数
Date(int year, int month = 1)
{
_years = year;
_month = month;
_day = 1;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date date1;//调用默认构造函数
Date date2(2018, 9, 4);//调用默认构造函数
}
构造函数体赋值:
在创建对象时,编译器通过调用构造函数,给对象中个成员一个合适的初始值
但是不能将其称作类对象的成员的初始化,构造函数体种操作只能将其称为赋初值。
而不能称作初始化。因为初始化只能初始化一次,而构造函数体内,可以给成员多次赋值
列表初始化:
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员列表”后面跟一个放在括号中的
初始值或表达式
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:初始化列表仅用于初始化类的数据成员,并不指定这些数据成员的初始化顺序,数据成员在类中定义顺序就是
在初始化列表中的初始化顺序
3:尽量避免使用成员初始化成员,成员的初始化顺序最好和定义顺序保持一致
4:类中包含以下成员,一定放在初始化列表位置进行初始化
- 引用成员变量
- const成员变量
- 类类型成员变量(该类有非缺省的构造函数)
构造函数作用:
构造函数不仅可以把对象构造成功,还可以给对象中各个成员变量一个初始值,有时候还具有类型转换的作用
- 构造&初始化对象
- 类型转换
class Date
{
public:
Date(int year)
:_year(year)
{ }
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date date1(2018);
date1 = 2019;
//用一个整形变量个日期类型对象赋值
//实际编译器会用2019构造一个无名对象,最后用无名对象给date1赋值
}
用explicit修饰的构造函数,将会抑制构造函数的隐式转换
析构函数:
当一个对象的生命周期结束时,编译系统会自动调用一个成员函数,这个成员函数即析构函数
析构函数是特殊函数,特征如下:
1:析构函数名是在类名前加字符~
2:无参数无返回值
3:一个类有且只有一个析构函数,若未定义系统生成默认的析构函数
4:对象的生命周期结束时,调用析构函数
class Date
{
public:
//析构函数
~Date()
{ }
private:
int _year;
int _month;
int _day;
};
析构函数不是删除对象,而是做一些对象删除前的相关清理工作。
class MyVector
{
public:
int *p = NULL;
MyVector(int size)
{
p = (int *)malloc(size*sizeof(int));
}
//析构函数需要完成释放空间的工作
~MyVector()
{
if (p)
{
free(p);//释放堆上的空间
p = 0;//将指针置空
}
}
private:
int *p;
};
拷贝构造函数
创建对象时使用同类对象进程初始化,这时所用的构造函数称为拷贝构造函数
拷贝构造函数是特殊函数,特征为:
1:拷贝构造函数是一个构造函数的重载
2:拷贝构造函数参数只有一个且必须引用传参,使用传值方式会引发无穷递归调用
3:若未显示定义,系统会默认生成拷贝构造函数,默认的拷贝构造函数会按照成员声明的顺序依次拷贝类的成员进行初始化
class Date
{
public:
Date()
{}
//拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date date1;
//下面两种用法都是调用拷贝构造函数
Date date2(date1);
Date date3 = date1;
}
为什么拷贝构造函数的参数使用传值会引发无穷递归调用?
如果拷贝构造函数中的参数不是一个引用,那么就相当于采用了传值的方式,而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。
运行算符重载
为了增强程序的可读性,c++支持运算符重载
运算符重载的特征为:
1 :operator + 合法的运算符 构成函数名
2: 重载运算符以后,不能改变运算符的 优先级,结合性,操作数个数
class Date
{
public:
Date()
{}
//拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// == 操作符的重载
bool operator == (const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date date1;
Date date2 = date1;//调用拷贝构造函数
date2 == date1;//调用 == 运算符重载
}
编译器对 == 操作符的重载处理
5个C++不能重载的运算符是哪些?
并不是所有的操作符都能被重载。除了. ,.* ,:: ,? : ,sizeof这几个运算符不能被重载,其他运算符都能被重载
类的赋值操作符重载
1:赋值运算符的重载是对一个已存在的对象进行拷贝赋值
2:当程序没有显式的提供一个以本类或本类的引用为参数的赋值运算符重载时,编译器会自动生成这样一个赋值运算符重载函数
class Date
{
public:
Date()
{}
//拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 赋值操作符的重载
Date& operator = (const Date& d)
//为什么operator=赋值函数需要一个 Date&的返回值
//原因有两个:
//①允许进行连续赋值
//②防止返回对象(返回对象也可以进行连续赋值)的时候调用拷贝构造函数和析构函数导致不必要的开销,降低赋值运算符等的效率。
{
if (this != &d)
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date date1;
Date date2 = date1;//调用拷贝构造函数
Date date3;
date3 = date1;//调用赋值运算符重载
}
类的const成员函数
const修饰普通变量
在C++中,const修饰的变量已经为一个常量,具有宏的属性,即在编译期间,编译器会将const所修饰的常量进行
替换。
const修饰类成员
1. const修饰类成员变量时,该成员变量必须在构造函数的初始化列表中初始化
2. const修饰类成员函数,实际修饰该成员函数隐含的this指针,该成员函数中不能对类的任何成员记性修改
3. 在const修饰的成员函数可能需要对类的某个成员变量进行修改,该成员变量只需被mutable关键字修饰即可
类的取地址操作符重载 及 const修饰的取地址操作符重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
class Date
{
public :
Date* operator &()
{
return this ;
}
const Date * operator&() const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
只有一种情况下,才会需要你自己重载这两个操作符,那就是你只想让别人获取到你指定的内容!