以日期类为例,说明:
class Date
{
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
d1.SetDate(2018, 6, 1);
d2.SetDate(2018, 5, 30);
d1.Display();
d2.Display();
return 0;
}
构造函数
- 概念
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时,由编译器自动调用,在对象的生命周期内只调用一次,保证每个数据成员都有一个合适的初始值。 - 特性
构造函数是特殊的成员函数,其特征如下:
- 函数名与类名相同
- 无返回值,写void都不行。
- 对象构造(对象实例化)时系统自动调用对应的构造函数。且在对象的生命周期内仅调用一次。
- 构造函数可以重载,实参决定了调用哪个构造函数。
- 构造函数可以在类中定义,也可以在类外定义。
- 如果类定义中没有给出构造函数,则C++编译器自动产生一个缺省的构造函数,但只要我们定义了一个构造函数,系统就不会自动 生成缺省的构造函数。
- 无参的构造函数和全缺省值的构造函数都认为是缺省构造函数,并且缺省的构造函数只能有一个。
- 初始化列表(可以不用)
- 构造函数不能用const修饰
- 构造函数不能为虚函数
class Date
{
public:
//1.无参构造函数
Date()
{}
//2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//3.缺省参数的构造函数
Date(int year=1999, int month=1, int day=1)
{
_year = year;
_month = month;
_day = day;
}
//4.半缺省参数的构造函数(不常用)
Date(int year = 1999, int month = 1)
{
_year = year;
_month = month;
_day = 1;
}
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
析构函数
- 概念
特殊成员函数,在对象的生命周期结束时,由编译器自动来调用,清理对象中的资源 - 特性
析构函数是特殊的成员函数,其特征如下:
- 析构函数在类名(即构造函数名)前加上字符~
- 无返回值
- 一个类有且只有一个析构函数。若无显示定义,系统会自动生成缺省的析构函数
- 对象生命周期结束时,C++编译系统自动调用析构函数
- 注意析构函数体内并不是删除对象,而是做一些清理工作
class MyVector
{
public :
MyVector (int size)
{
_ptr = (int *)malloc( size*sizeof (int));
} // 这里的析构函数需要完成清(shi)理(fang)工(kong)作(jian)。
~ MyVector ()
{
if (_ptr )
{
free(_ptr );//释放堆上的空间
_ptr = 0; //将指针置为空
}
}
private :
int* _ptr ;
};
拷贝构造函数
- 概念
只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数称为拷贝构造函数。 特性
- .拷贝构造函数其实是一个构造函数的重载,构造函数的性质拷贝构造函数均满足
- 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用
- 若未显示定义,系统会默认生成默认的拷贝构造函数。 默认的拷贝构造函数会按照成员的声明顺序依次拷贝类成员进行初始化。
使用场景
对象实例化对象
作为函数参数
作为函数返回值
class Date
{
public:
//1.无参构造函数
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 + 合法的运算符
构成函数名(举例:重载<运算符的函数名:operator< )
2. 重载运算符以后,不能改变运算符的优先级/结合性/操作数个数。
5个C++不能重载的运算符是哪些?
.* / :: / sizeof / ?: / .
类的赋值运算符重载
- 赋值运算符的重载是对一个已存在的对象进行拷贝赋值 。
- 当程序没有显式地提供一个以本类或本类的引用为参数的赋值运算符重载函数时,编译器会自动生成这样一个赋值运算符重载函数
class Date
{
public :
Date()
{} // 拷贝构造函数
Date (const Date& d)
{
_year = d ._year;
_month = d ._month;
_day = d ._day;
}
// 赋值操作符的重载
// 1.思考为什么operator=赋值函数需要一个 Date&的返回值, 使用void做返回值可以吗? 请验证
Date& operator = (const Date& d)
{
// 2.这里的if条件判断是在检查什么?
if (this != &d)
{
this->_year = d. _year;
this->_month = d. _month;
this->_day = d. _day;
}
return *this ;
}
bool operator ==(const Date&d)
{
return _year == d._year && _month == d._month && _day == d._day;
bool operator!=(const Date&d)
{
return this != &d;
}
//前置++
Date& operator++()
{
_day += 1;
return *this;
}
//后置++
Date operator++(int)
{
Date temp(*this);
_day += 1;
return temp;
}
private:
int _year ;
int _month ;
int _day ;
};
void Test ()
{
Date date1 ;
Date date2 = date1; // 调用拷贝构造函数
Date date3 ;
date3 = date1 ; // 调用赋值运算符的重载
Date date4;
Date date5;
date4.operator=(date5.operator=(d1));
Date date6;
date6 = date1++;
Date d7;
date7 = ++date2;
}
类的const成员函数
const修饰普通变量
在C++中,const修饰的变量已经为一个常量,具有宏的属性,即在编译期间,编译器会将const所修饰的常量进行替换
- const修饰形参,一般和引用同时使用
- const修饰返回值
const修饰类成员
- const修饰类成员变量,必须在构造函数的初始化列表中初始化
- const修饰类成员函数,实际修饰该成员函数隐含的this指针,该成员函数中不能对类的任何成员进行修改
this指针类型由Date* const
变为const Date* const
- 在const修饰的成员函数中要对类的某个数据成员进行修改,该数据成员定义声明是必须加mutable
关键字
const对象可以调用const成员函数
非const对象可以调用非const成员函数和const成员函数
const成员函数内可以调用其他const成员函数
非const成员函数内可以调用其他const成员函数和非const成员函数