复习:

1、

wKiom1aZ2V2hM-tNAAAjGs4m0dk649.png

2、重点:

不能重载的 

wKiom1aZ2dejtpspAAAzC33djkc368.png

3、赋值运算符重载

wKioL1aZ24zAdZFJAAAyeTc4Upc324.png

4、

wKiom1aZ2_bD9t7iAAAZcJRErFU831.png

5、为什么要有返回值

return *this,可以不要

为了遵从基本类的赋值,为了支持连续赋值

wKioL1aZ3S7g_nRpAAAZDCD0Rts005.png

6、

wKioL1aZ3mPhweX5AAA3plu_QSk261.png

7.

重载:函数名

运算符重载(重载符号):==替换成operator==

8、

wKiom1aZ4UKBrWZOAABRkX-_ScY797.png正式上课:

1、深入探索构造函数

初始化的两种方式:

(1)在函数体内初始化

class Date
{
public:
	Date(int year = 2016, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

(2)初始化列表

class Date
{
public:
	Date(int year , int month , int day )
		:_year = year,
		_month = month,
		_day = day
	{
		;
	}
private:
	int _year;
	int _month;
	int _day;
};

为什么有了第一种还要第二种来初始化?
答:因为高效

(3)


2、拷贝构造的次数

wKiom1aZ6xvhGR8dAAAwjtSv-EI417.png

wKiom1aZ7HGyqZsJAABD3GP1e1M944.png

两种初始化的方法可以结合起来使用

public:
	Date(int year , int month , int day )
		:_year = year,
		_month = month
		
	{
		;_day = day;
	}

不用参数列表初始化初始化也会初始化为随机值

所以建议用列表初始化


3、必须在表中初始化

(1)常量成员变量

wKiom1aZ7l2B2w0QAAAiFhSn97s861.png

(2)引用

wKioL1aZ716ij-DLAAAgUrNyxNw645.png

(3)没有缺省构造函数的类成员变量。

没有写缺省构造函数,系统无法使用

解决方法:

a)加缺省

2)用列表初始化(._t(hour))

4、成员变量按声明顺序依次初始化,而非初始化列表出现的顺序

class Date
{
public:
	Date(int x)
		: _day(x)
		, _month(_day)//随机值(不管列表中出现的顺序,都按照声明的顺序)
		, _year(x)
	{
		cout << "Date ()" << endl;
	}

	void Display()
	{
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl;
	}

private:
	int _year;     // 年
	int _month;    // 月
	int _day;      // 日
}

所以习惯上下保持一致


下一个开始:

类和对象--const&内联&静态成员&友元

1、const修饰的成员函数

wKiom1aZ8kSRx55cAAAtMFMstgQ237.png

附:

(1)在成员函数后面加const,const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数内不会被改变

(2)调用成员函数的对象不能改变

(3)const函数,非const和const都可以调用

(4)SetDate()无const说法

思考:

(1)const对象可以调用非const成员函数和const成员函数吗?

(2)非const对象可以调用非const成员函数和const成员函数吗?

(3)const成员函数内可以调用其它的const成员函数非const成员函数吗?

wKiom1aaDmSS1skTAABCNsa3fwc081.png

(4)非const成员函数内可以调用其它的const成员函数非const成员函数吗?

2、取地址运算符重载(这两个默认成员函数一般不用重新定义)

Date* operator&()
{
	return this;
}//系统生成默认的

wKioL1aaEViABLatAABCNsa3fwc041.png2、

cout<<&d<<endl;//--->const Date* operator&()const

3、inline(内联)

(1)以inline修饰的函数叫做内联函数,编译时C++编译器会调用内联函数的地方展开,没有

函数压栈的开销,内联函函数提升程序运行的效率

wKioL1aaFTSDIGMdAAAtJPc7CTU723.png

特点:

(1)inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的的函数不适宜使用内联。

(2)inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

(3)inline必须函数定义放在一起,才能成为内联函数,仅将inline放在声明前是不起不作用的。(4)定义在类内的成员函数默认定义为内联函数。

思考:

C++建议以const/枚举/内联去替代宏,为什么?

1、都可以定义常量const,enum,#define

但是#define无类型安全性检查,而其他的有

2、#define不可以调试,后面的两种可以调试

3.为什么内联

#define出了可以定义宏常量,

宏函数(相当于inline,但是inline如果错误的话,编译不通过)

(1)#define,无法调试,inline可以调试(一样高效,但是可以调试)

(2)#define,容易出错,例如:ret=ADD(a,b)*c//a+b*c,inline如果错误的话,编译不通过

考点:c和c++的差异

4、友元


作业:实现万年历

  1. 构造函数

Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

年月日有可能非法

解决方法:

(1)添加断言

assert(year>=1900&&_month>0&&_month<13&&_day>0&&_day<=_GetMonthDay(year,day))

(2)_GetMonthDay函数

int GetMonthDay(int year, int month)
	{
		int monthArray[13] = {0, 31, 28, 31, 30};

		int day = monthArray[month];

		if (month == 2 && IsLeapYear(year))
		{
			day += 1;
		}

		return day;
	}

(3)构造函数中

如果错误,则非法日期定义为初始值

if ()//正确
{
    ;//直接初始化
}
else//错误日期
{
    ;//初始化为初始日期或则断言assert(flase);
}

(4)加法,日期加天数

wKiom1aaPRWSIeezAAAa0GRXDp0112.png

        Date operator+()//有可能是负数
{
	Date tmp(*this);
	if (day < 0)
		return *this-> - (-day));
	else
	{
		while (tmp._day>GetMonthday(tmp, _year, tmp._month))
		{
			tmp._day -= _GetMonthDay(tmp, _year, tmp._month);
			if (tmp.month == 12)
			{
				tmp._year++;
				tmp._month = 1;
			}
			else
			{
				++tmp.month;
			}
		}
		
	}
	return tmp;
}