IMG20201003093205.jpg

弃坑黑马程序员C++

纸上得来终觉浅,之前一直看着黑马程序员的视频,一边看一边敲,敲了两个星期,感觉自己只会跟着老师敲,脑子动的太少了,进步不明显,感觉这种方式不适合我

于是弃坑去图书馆借了本实体书开始对着学

《C++从零开始学》---王英英

随书资料

扫码自取

IMG20201003093200.jpg

里面有视频讲解+随书源代码+课程PPT

该书学习笔记

面向对象概念

面向对象编程(Object Oriented Programming,OOP)是一种程序设计方法,它的核心是将现实世界中的概念、过程和事务抽象成C++中的模型,使用这些模型来进行程序的设计和构建。

1.对象

对象的概念既是面向对象编程的概念,也是现实生活中的概念,就是使用对象这个概念将程序设计和现实日常生活联系起来。对象在现实生活中可以指自然物体等,每个对象都含有静态属性,比如长、宽、高等,这些属性就抽象成一个类的数据成员。每个对象都有动态属性,通过动态属性与外界相互联系,这就可以抽象成类的成员函数。

2.抽象

抽象的概念在现实中是一个常用的概念,就是将一个事务对象进行归纳总结的过程。在面向对象编程中,抽象是指将有相同特征的事务抽象成一个类,一个事务成为这个类的一个对象。

3.封装

封装在现实生活中的理解是将某个事务封闭在一个环境中,与外界隔离开来。在面向对象编程中,封装就是将一个类的数据成员和成员函数封闭在一个对象中,每个对象之间相互独立,互补干扰,只留下一个公开接口与外界进行通信。

4.继承

在面向对象的编程中,继承的概念与现实中的继承概念相似,就是某一个类继承了另一个类的特性,继承的类就称为派生类,接被继承的类就称为基类。派生类中包含基类的数据成员和成员函数,同时也有自己的数据成员和成员函数。

5.多态

现实生活中,每个个体接收到相同的信息,翻译不同。在面向对象的编程中,也有类似的情况,对于相似的类的对象,接受到同一个指令,它们执行的操作不同,称之为多态性。在面向对象程序设计中,多态主要表现在同一个基类继承不同派生类的对象,这些对象同一消息产生不同的响应。

命名空间

引入命名空间是为了解决不同模块(函数)下相同标识符冲突的问题,提高标识符的利用率

#include <iostream>
#include <string>
using namespace std;
namespace myown1 {
	string user_name = "myown1";
}
namespace myown2 {
	string user_name = "myown2";
}
//两个在不同命名空间中定义的名字相同的变量
int main() 
{
	cout << "Hello, "
		<< myown1::user_name//用命名空间限制符myown1访问变量user_name
		<< endl;
	cout << "Hello, "
		<< myown2::user_name//用命名空间限制符myown2访问变量user_name
		<< endl;

	




	system("pause");
	return 0;
}

2.7.1.jpg

求解一元二次方程ax^2+bx+c=0的根

#include <iostream>
#include <string>
//常用数学工具库
//官方网址       http://www.cplusplus.com/reference/cmath/
#include <cmath>
using namespace std;
//求解一元二次方程ax^2+bx+c=0的根
int main()
{
	float a, b, c;//系数
	float x1, x2;
	cout << "请输入a的值:" << endl;
	cin >> a;
	cout << "请输入b的值:" << endl;
	cin >> b;
	cout << "请输入c的值:" << endl;
	cin >> c;
	cout << "您输入的方程为:" << a << "x^2+" << b << "x+" << c << "=0" << endl;

	float t = b * b - 4 * a * c;//得塔
	if (t < 0) 
	{
		cout << "此方程无实数根" << endl;
	}
	else
	{
		//求根公式
		x1 = (-b + sqrt(t)) / (2 * a);//sqrt(t):对t开平方
		x2 = (-b - sqrt(t)) / (2 * a);

		cout << "一个根x1=" << x1 << endl;
		cout << "一个根x2=" << x2 << endl;
	}



	system("pause");
	return 0;
}

2.7.2.jpg

判断输入的一个字符是否为大写

判断输入的一个字符是否为大写
若是:转化成小写
若不是:原样输出

#include <iostream>
using namespace std;

//判断输入的一个字符是否为大写
//若是:转化成小写
//若不是:原样输出
int main()
{
	////获取a和A的ASCII码
	//char ASC_a = 'a';
	//cout << (int)ASC_a << endl;//a的ASCII码为:97

	//char ASC_A = 'A';
	//cout << (int)ASC_A << endl;//A的ASCII码为:65

	//将字符类型char前面加上(int)强制转换成整型即可得到该字符的ASCII码

	char x;
	cout << "请输入需要判断的字符:" << endl;
	cin >> x;
	
	(int)x >= 65 && (int)x<=96 ? 
		cout << "此字符为大写字母,转化成小写字母"<<char((int)x+32)<< endl :
	    cout << "此字符为小写字母" << x << endl;



	system("pause");
	return 0;


}

2.7.4.jpg

判断某一年是否是闰年

闰年的条件是:1.能被4整除而不能被100整除 2.同时能被100和400整除

#include <iostream>
using namespace std;

//判断某一年是否是闰年
//闰年的条件是:1.能被4整除而不能被100整除   2.同时能被100和400整除

int main()
{
	cout << "请输入要判断的年份:" << endl;
	int x = 0;
	cin >> x;

	if (x % 4 == 0 && x % 100 != 0) 
	{
		cout <<x<< "年为闰年!" << endl;
	}
	else if (x % 100 == 0 && x % 400 == 0)
	{
		cout << x << "年为闰年!" << endl;
	}
	else
	{
		cout << x << "年不是闰年!" << endl;
	}



	system("pause");
	return 0;


}

2.7.5.jpg

反向输出

从键盘上读取4个字符,把它们放在一个4字节的整型变量中,把这个变量的值显示为一个16进制;分解变量的4个字节,以相反的顺序输出它们,先输出低位字节

#include <iostream>
using namespace std;


//从键盘上读取4个字符,把它们放在一个4字节的整型变量中,把这个变量的值显示为一个16进制
//分解变量的4个字节,以相反的顺序输出它们,先输出低位字节
int main()
{
	cout << "请输入4个字符" << endl;
	char a[4];
	cin >> a[0] >> a[1] >> a[2] >> a[3] ;
	////输出测试----是否接收成功
	//for (int i = 0;i < 4;i++)
	//{
	//	cout << a[i] << endl;
	//}
	int x;
	x = (int)a[0]*1000+ (int)a[1] * 100+ (int)a[2] * 10+(int)a[3];

	cout << hex <<"转成十六进制为:" <<x << endl;//通过hex输出16进制数

	cout <<  a[3] 
		<< a[2]
		<< a[1]
		<< a[0]
		<< endl;

	system("pause");
	return 0;


}

2.7.6.jpg

利用三角形三条边求三角形面积

#include <iostream>
#include <cmath>
using namespace std;


//输入三角形的三条边长,计算三角形的面积
int main()
{
	float a, b, c, s, area;
	cout << "请输入第一条边的长度:" << endl;
	cin >> a;
	cout << "请输入第二条边的长度:" << endl;
	cin >> b;
	cout << "请输入第三条边的长度:" << endl;
	cin >> c;
	//判断是否可以构成三角形
	if (a + b > c && a + c > b && b + c > a) 
	{
		//海伦公式
		s = (a + b + c) / 2;
		area = sqrt(s * (s - a) * (s - b) * (s - c));
		cout << "此三角形面积为:" << area << endl;
	}
	else {
		cout << "此三条边构不成三角形!" << endl;
	}
	


	system("pause");
	return 0;


}

2.7.7.jpg

求解自然对数e

自然对数e的计算公式为:
e=1+1/1!+1/2!+1/3!+1/4!+...+1/n!+r
当n充分大时,可计算e的近似值 其中r为误差

#include <iostream>
using namespace std;

#define EPX 0.1e-10 //设置最小误差为0.1^-10

//自然对数e的计算公式为:
//e=1+1/1!+1/2!+1/3!+1/4!+...+1/n!+r
//当n充分大时,可计算e的近似值 其中r为误差
int main()
{
	int n = 1;
	double e = 1, r = 1;
	do {
		e = e + r;
		n++;
		r = r / n;

	} while (r > EPX);
	cout <<"自然对数的近似值为:" << e << endl;
	system("pause");



}

2.7.8.jpg

递归调用求解数组

现有一个数列,已知an=2*a(n-1)+3,并且a1=1,求解a1~a10的值

#include <iostream>
using namespace std;

int f(int a) {
	if (a == 1) {
		return 1;
	}
	else 
	{ 
		a = 2 * f(a-1)  + 3; 
	}
	return a;
}


//现有一个数列,已知an=2*a(n-1)+3,并且a1=1,求解a1~a10的值
int main()
{
	//测试输出
	//cout << f(2) << endl;

	for (int i = 1;i < 11;i++)
	{
		cout << f(i) << endl;
	}



	system("pause");
	return 0;


}

6.3.1.jpg

汉诺塔问题

汉诺塔问题:
汉诺塔来源于印度传说的一个故事,大梵天创造世界时作了三根金刚石柱子,在一根柱子上从上往下从小到大顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘,只能移动在最顶端的圆盘。

#include <iostream>
using namespace std;


//汉诺塔问题
//汉诺塔来源于印度传说的一个故事,大梵天创造世界时作了三根金刚石柱子,
//在一根柱子上从上往下从小到大顺序摞着64片黄金圆盘。
//上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
//并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘,
//只能移动在最顶端的圆盘。


//算法思想:
//1.把A柱上的n-1个盘子移动到B柱上(借助C柱)
//2.把A柱的最后一个盘子移动到C柱
//3.把B柱的n-1个盘子移动到C柱(借助A柱)

int i = 1;//记录移动的步数

void move1(char A, char B)//移动一个盘子
{
	
	cout <<"第"<<i++<< "步移动:" << A << "-->" << "至" << B << endl;

}
void moven(int n, char A, char B, char C) //A柱上的n个盘子 -------------> C柱
{
	if (n == 1) {
		move1(A, C);
	}
	else
	{
		moven(n - 1, A, C, B);//A柱上的n-1个盘子 -------------> B柱
		move1(A, C);//A柱上的最后一个盘子 -------------> C柱
		moven(n - 1, B, A, C);//B柱上的n-1个盘子 -------------> C柱
	}

}

int main()
{
	int m;

	cout << "请输入初始圆盘数量:" << endl;
	cin >> m;
	cout << "移动顺序为:" << endl;
	moven(m, 'A', 'B', 'C');
	cout <<"移动"<<m<<"片圆盘"<< "一共需要" << i-1 << "步操作完成移动" << endl;



	system("pause");
	return 0;


}

6.7.1.jpg

二维数组输出字符字母

#include <iostream>
using namespace std;



int main()
{
	int a[7][7] = {
		{1,1,1,1,1,1,1},
		{0,0,0,0,0,1,0},
		{0,0,0,0,1,0,0},
		{0,0,0,1,0,0,0},
		{0,0,1,0,0,0,0},
		{0,1,0,0,0,0,0},
		{1,1,1,1,1,1,1}
	};
	int b[7][7] = {
	{1,0,0,0,0,0,1},
	{0,1,0,0,0,1,0},
	{0,0,1,0,1,0,0},
	{0,0,0,1,0,0,0},
	{0,0,1,0,1,0,0},
	{0,1,0,0,0,1,0},
	{1,0,0,0,0,0,1}
	};

	for (int i = 0;i < 7;i++)//Z
	{
		for (int j = 0;j < 7;j++) 
		{
			if (a[i][j] == 1)
			{
				cout << "*";
			}
			else
			{
				cout << " ";
			}
		}
		cout << endl;
	}
	cout << endl;


	for (int i = 0;i < 7;i++)//Z
	{
		for (int j = 0;j < 7;j++)
		{
			if (a[i][j] == 1)
			{
				cout << "*";
			}
			else
			{
				cout << " ";
			}
		}
		cout << endl;
	}
	cout << endl;


	for (int i = 0;i < 7;i++)//X
	{
		for (int j = 0;j < 7;j++)
		{
			if (b[i][j] == 1)
			{
				cout << "*";
			}
			else
			{
				cout << " ";
			}
		}
		cout << endl;
	}

	system("pause");
	return 0;


}

7.1.1.jpg

字符串处理函数

常用的字符串处理函数包括puts函数与 gets 函数、字符串复制strcpy函数、字符串连接函数strcat函数、字符串比较函数strcmp函数、求字符串长度strlen函数等。

  1. 字符串输出函数
puts(str);

输出指定字符串,参数可以为字符串常量

  1. 字符串输入函数
gets(str);

输入字符串至字符数组str中,输入的字符串可以包含空格。函数返回值是字符数组str的首地址;

  1. 字符串复制函数
strcpy(str1,str2);

将str2的值复制到str1中,实际上完成字符串的赋值操作。要求str1的长度大于str2的长度,第二个参数可以是字符串常量。

  1. 字符串连接函数
strcat(str1,str2);

将str2的值连接到str1中原有值的后面。注意str1必须足够大,以便能容纳两个字符数组中的所有值。连接完成后,两个字符串并成一个字符串,第一个字符串后面的结束符“\0”自动取消。

  1. 字符串比较函数
strcmp(str1,str2);

比较str1和str2,若两者相同,则返回函数值为0;若str1>str2,则返回函数值为一个正整数;若str1<str2,则返回函数值为一个负整数。两个参数可以是字符串常量。

字符串比较规则与其他语言相同,将两个字符串中的字符从左到右依次比较,如果全部字符相同,则认为相等;若出现不同字符,则以第一个不同字符比较结果为准。

  1. 字符串的实际长度函数
strlen(str);

函数的返回值为字符串的实际长度。

  1. 大写字母转换成小写字符函数
strlwr(str);

将字符串中大写字母转换成小写字母。

  1. 小写字母转换成大写字符函数
strupr(str);

将字符串中小写字母转换成大写字母。

判断字符串中有多少个整数

输入一个字符串,内有数字和非数字字符,判断字符串中有多少个整数,连续的数字算一个整数

#include<iostream>
#include<string>
#include<iomanip>
using namespace std;
//该函数将字符串中的连续数字存入整型数组a中,并返回a中整数的个数
int findInteger(char* p, int* a)
{
	int j, n = 0, i, k;
	char temp[100];//存放连续的数字,以便转换成整数
	for (i = 0;p[i] != '\0';i++)   //    '0'表示字符串结束符
	{
		j = 0;
		while (p[i] >= '0' && p[i] <= '9')//比较ASCII码,判断第i个字符是否是数字
		{
			temp[j] = p[i];//是的话,存入temp数组
			j++; 
			i++;
		}
		if (j != 0)//如果存在连续的数字
		{
			*a = atoi(temp);//atoi函数的功能是将字符串转换成正整数
			a++;
			n++;
			for (k = 0;k < j;k++)//将数组temp清零,以便存放下一个数字
				temp[k] = 0;
			i--;
		}
	}
	return n;
}
int main()
{
	int i, m, a[100];
	char line[100];
	cout << "请输入一个字符串:" << endl;
	cin >> line;
	m = findInteger(line, a);
	cout << "字符串中共有:" << m << "个整数" << endl;

	for (i = 0;i < m;i++) 
	{
		cout << a[i] << endl;
	}

	cout << endl;
	system("pause");
	return 0;
}

8.9.1.jpg

学生成绩信息登记表

学生成绩信息登记表:
每个学生的数据包括:学号,姓名,和语数英三门的成绩
实现效果:
1.从键盘输入3名学生的数据
2.显示每个学生的三门课的平均分
3.显示每门课的全班平均分
4.按平均分高低排名,并按名次降序输出学生的所有数据

//学生成绩信息登记表
//每个学生的数据包括:学号,姓名,和语数英三门的成绩
//实现效果:
//1.从键盘输入3名学生的数据
//2.显示每个学生的三门课的平均分
//3.显示每门课的全班平均分
//4.按平均分高低排名,并按名次降序输出学生的所有数据
#include <iostream>
using namespace std;
#define STU 3   //设置学生的人数

//定义学生结构体
struct Student {
	int num;//学号
	string name;//姓名
	int gradeChinese;//语文成绩
	int gradeMath;//数学成绩
	int gradeEnglish;//英语成绩
};
//得到输入的学生的信息
void getStudentInfo(Student a[STU]) {
	for (int i = 0;i < STU;i++)
	{
		cout << "请输入第" << i + 1 << "个同学的" << "学号:" ;
		cin >> a[i].num;
		cout << "请输入第" << i + 1 << "个同学的" << "姓名:" ;
		cin >> a[i].name;
		cout << "请输入第" << i + 1 << "个同学的" << "语文成绩:" ;
		cin >> a[i].gradeChinese;
		cout << "请输入第" << i + 1 << "个同学的" << "数学成绩:" ;
		cin >> a[i].gradeMath;
		cout << "请输入第" << i + 1 << "个同学的" << "英语成绩:"  ;
		cin >> a[i].gradeEnglish;
	}
	cout << endl;
}
//计算每个学生的三门平均分
void averageStudent(Student a[STU]) {
	for (int i = 0;i < STU;i++) 
	{
		cout << "第" << i + 1 << "名同学的语数英平均分为:"
			<< (a[i].gradeChinese + a[i].gradeEnglish + a[i].gradeMath) / 3
			<< endl;
	}
	cout << endl;
}

//计算每门课的全班平均分
void averageClass(Student a[STU]) {
	int a_math = 0;//全班数学总分
	for (int i = 0;i < STU;i++)
	{
		a_math = a_math + a[i].gradeMath;
	}
	int a_chinese = 0;//全班语文总分
	for (int i = 0;i < STU;i++)
	{
		a_chinese = a_chinese + a[i].gradeChinese;
	}
	int a_english = 0;//全班英语总分
	for (int i = 0;i < STU;i++)
	{
		a_english = a_english + a[i].gradeEnglish;
	}
	cout << "全班语文的平均分为:"<<a_chinese/STU<<endl;
	cout << "全班数学的平均分为:"<<a_math/STU<<endl;
	cout << "全班英语的平均分为:"<<a_english/STU<<endl;
	cout << endl;
}

//按平均分降序排名
void rankStudentGrade(Student a[STU]) {
	int b[STU];//定义b数组存放每个人的平均分
	for (int i = 0;i < STU;i++)
	{
		b[i] = (a[i].gradeChinese + a[i].gradeEnglish + a[i].gradeMath) / 3;
	}
	//把b数组数据存一份数据给c数组
	//b数组中存放的是未排序的平均分,c数组中存放的是排序过后的平均分
	int c[STU];
	for (int i = 0;i < STU;i++)
	{
		c[i] = b[i];
	}
	//冒泡排序
	for (int i = 0;i < STU - 1;i++)
	{
		for (int j = 0;j < STU - 1 - i;j++) 
		{
			int temp = 0;
			if (c[j] < c[j + 1]) 
			{
				temp = c[j + 1];
				c[j + 1] = c[j];
				c[j] = temp;
			}
		}
	}
	//测试输出
	//for (int i = 0;i < STU;i++)
	//{
	//	cout << "按平均分降序排名为:" << c[i] << endl;
	//}

	//比较b和c数组,输出对应平均分同学的成绩
	for (int i = 0;i < STU;i++)
	{
		for (int j = 0;j < STU;j++)
		{
			if (c[i] == b[j])
			{
				cout << "第" << i + 1 << "名是:" << a[j].name << "  平均分为:" << b[j] 
					<<"  学号为:"<<a[j].num
					<< "  语文成绩为:" << a[j].gradeChinese
					<< "  数学成绩为:" << a[j].gradeMath
					<< "  英语成绩为:" << a[j].gradeEnglish
					<< endl;
			}
		}
	}

}

int main()
{
	Student a[STU];

	getStudentInfo(a);//得到输入的学生的信息

	//cout << "第三位同学的英语成绩为:" << a[STU - 1].gradeEnglish << endl;//测试是否接收成功

	averageStudent(a);//计算每个学生的三门平均分

	averageClass(a);//计算每门课的全班平均分

	rankStudentGrade(a);//按平均分降序排名

	system("pause");
	return 0;


}

9.5.1.jpg

--------------------------降序输出算法改进-----------------------------

//学生成绩信息登记表
//每个学生的数据包括:学号,姓名,和语数英三门的成绩
//实现效果:
//1.从键盘输入3名学生的数据
//2.显示每个学生的三门课的平均分
//3.显示每门课的全班平均分
//4.按平均分高低排名,并按名次降序输出学生的所有数据
#include <iostream>
using namespace std;
#define STU 3   //设置学生的人数

//定义学生结构体
struct Student {
	int num;//学号
	string name;//姓名
	int gradeChinese;//语文成绩
	int gradeMath;//数学成绩
	int gradeEnglish;//英语成绩
};
//得到输入的学生的信息
void getStudentInfo(Student a[STU]) {
	for (int i = 0;i < STU;i++)
	{
		cout << "请输入第" << i + 1 << "个同学的" << "学号:" ;
		cin >> a[i].num;
		cout << "请输入第" << i + 1 << "个同学的" << "姓名:" ;
		cin >> a[i].name;
		cout << "请输入第" << i + 1 << "个同学的" << "语文成绩:" ;
		cin >> a[i].gradeChinese;
		cout << "请输入第" << i + 1 << "个同学的" << "数学成绩:" ;
		cin >> a[i].gradeMath;
		cout << "请输入第" << i + 1 << "个同学的" << "英语成绩:"  ;
		cin >> a[i].gradeEnglish;
	}
	cout << endl;
}
//计算每个学生的三门平均分
void averageStudent(Student a[STU]) {
	for (int i = 0;i < STU;i++) 
	{
		cout << "第" << i + 1 << "名同学的语数英平均分为:"
			<< (a[i].gradeChinese + a[i].gradeEnglish + a[i].gradeMath) / 3
			<< endl;
	}
	cout << endl;
}

//计算每门课的全班平均分
void averageClass(Student a[STU]) {
	int a_math = 0;//全班数学总分
	for (int i = 0;i < STU;i++)
	{
		a_math = a_math + a[i].gradeMath;
	}
	int a_chinese = 0;//全班语文总分
	for (int i = 0;i < STU;i++)
	{
		a_chinese = a_chinese + a[i].gradeChinese;
	}
	int a_english = 0;//全班英语总分
	for (int i = 0;i < STU;i++)
	{
		a_english = a_english + a[i].gradeEnglish;
	}
	cout << "全班语文的平均分为:"<<a_chinese/STU<<endl;
	cout << "全班数学的平均分为:"<<a_math/STU<<endl;
	cout << "全班英语的平均分为:"<<a_english/STU<<endl;
	cout << endl;
}

//按平均分降序排名
void rankStudentGrade(Student a[STU]) {
	int b[STU];//定义b数组存放每个人的平均分
	for (int i = 0;i < STU;i++)
	{
		b[i] = (a[i].gradeChinese + a[i].gradeEnglish + a[i].gradeMath) / 3;
	}
	
	for (int i = 0;i < STU - 1;i++)
	{
		
		for (int j = 0;j < STU - 1 - i;  j++)
		{
			if (b[j] < b[j+1])
			{
				Student temp;
				temp = a[j];
				a[j] = a[j+1];
				a[j+1] = temp;


				int temp1 = 0;
				temp1 = b[j];
				b[j] = b[j + 1];
				b[j + 1] = temp1;

			}
		}
	}


	for (int j = 0;j < STU;j++)
	{
		cout << "第" << j + 1 << "名是:" << a[j].name 
			<<"平均分为:"<< (a[j].gradeChinese + a[j].gradeEnglish + a[j].gradeMath) / 3
			<< "  学号为:" << a[j].num
			<< "  语文成绩为:" << a[j].gradeChinese
			<< "  数学成绩为:" << a[j].gradeMath
			<< "  英语成绩为:" << a[j].gradeEnglish
			<< endl;
	}
}

int main()
{
	Student a[STU];

	getStudentInfo(a);//得到输入的学生的信息

	//cout << "第三位同学的英语成绩为:" << a[STU - 1].gradeEnglish << endl;//测试是否接收成功

	averageStudent(a);//计算每个学生的三门平均分

	averageClass(a);//计算每门课的全班平均分

	rankStudentGrade(a);//按平均分降序排名

	system("pause");
	return 0;


}

9.5.2.jpg

类的定义

类是有不同数据类型的数据与这些数据相关的操作封装在一起的集合。

类与结构体有些类似,但是结构体中并没有与数据相关的操作

#include <iostream>
using namespace std;

class Clock//时钟类的声明
{
public://外部接口,共有成员函数
	void setTime(int newH, int newM, int newS);

	void showTime(){
		cout << hour << ":" << minute << ":" << second << endl;
	
	}

private://私有数据成员
	int hour, minute, second;

};
//时钟类成员函数的具体实现
//成员函数:在类中说明原型,可以在类外给出函数体实现,也可以在类的内部直接编写函数体
void Clock::setTime(int newH, int newM, int newS)
{
	hour = newH;
	minute = newM;
	second = newS;
}


int main()
{
	Clock myclock;
	Clock* tClock;//创建类对象指针,对象指针是一个对象在内存中的首地址
	tClock = &myclock;
	myclock.setTime(14, 57, 30);
	myclock.showTime();
	tClock->showTime();//用对象的指针引用对象成员或数组元素使用操作符“->”


	system("pause");
	return 0;


}

10.1.3.1.jpg

私有成员:
私有成员用private声明(若私有成员紧接着类名称,则可省略关键字),私有类型的成员只允许本类的成员函数来访问,而类外部的任何访问都是非法的

#include <iostream>
using namespace std;

class Test {
private://私有成员函数类外不能够直接访问
	int number;

public:
	int returnNum()
	{
		return number;
	}
	void setNum(int a) {
		number = a;
	}
};


int main()
{
	Test test;
	//test.number = 20;   //错误,私有成员不能外部访问
	test.setNum(5201314);
	cout<<test.returnNum()<<endl;


	system("pause");
	return 0;


}

10.5.1.jpg

静态数据成员:
静态数据成员的目的是实现数据之间共享的问题。使用全局变量也可以实现数据共享,但是全局变量有其局限性。(1。不能保证值的正确性;因为其作用域是全局,所以程序范围内都可以修改它的值,如果出现错误非常难以发现。
2。如果在多线程中使用全局变量,你的程序将会错的一塌糊涂。多线程会修改另一个线程使用的全局变量的值,如果不注意,一旦出错后果不堪设想。)
静态数据成员对同一个类的多个对象是所共有的,存储在固定的内存空间,功所有该类的对象共同使用,每个类的对象都可以更新静态成员的值,只要有一个对象对该静态成员函数进行更新了,那么其他的对象访问该静态数据时,访问的就是该类最新更新的值。

#include <iostream>
using namespace std;

class Myclass
{
public:
	int myclass(int c, int m, int e);
	void getNum() {
		cout << "班级总分为:" << sum << endl;
	}

private:
	int C, M, E;
	static int sum;//静态数据成员
};
//静态数据成员
int Myclass::sum = 0;

int Myclass::myclass(int c, int m, int e)
{
	C = c;
	M = m;
	E = e;
	sum += C + M + E;

	return sum;
}

int main()
{

	Myclass wang,han,zang;
	wang.myclass(10, 0, 0);
	han.myclass(20, 0, 0);
	zang.myclass(30, 0, 0);

	wang.getNum();
	han.getNum();
	zang.getNum();


	system("pause");
	return 0;
}

10.6.1.jpg

栈的实现

栈的特点:先进后出

#include <iostream>
using namespace std;
const int MAX = 6;//设置栈的长度为6

class STACK
{
private:
	int data[MAX];
	int top;
public:
	STACK(void){
		top = 0;
		cout << "栈已被初始化!" << endl;
	}
	~STACK(void){
		cout << "栈已被销毁!" << endl;
	}
	bool isEmpty(void);//判断栈是否为空
	void push(int a);//进栈
	int pop(void);//出栈
};
bool STACK::isEmpty(void) {
	return top == 0 ? true : false;
}

void  STACK::push(int a) {
	if (top == MAX) {//栈若是满了,返回
		cout << "栈已经满了!" << endl;
		return;

	}
	//未满,存入数组
	data[top] = a;
	top++;
}

int STACK::pop(void)
{
	if (top == 0) {//栈若为空,返回
		cout << "栈是空的!" << endl;
		return 0;
	}
	//非空,弹出栈顶数组
	top--;
	return data[top];
}
int main()
{
	STACK s1, s2;
	for (int i = 0;i < MAX;i++)
	{
		s1.push(i);
	}
	for (int i = 0;i < MAX;i++)//往s1栈中压入数据
	{
		cout<<s1.pop()<<"  ";
	}

	for (int i = 0;i < MAX;i++)//从s1栈中弹出数据
	{
		s1.push(2 * i);
	}
	for (int i = 0;i < MAX;i++)//将s1栈中的数值乘以2,压入s2栈中
	{
		s2.push(s1.pop());
	}
	cout << endl;
	do {//从s2栈中弹出数据
		cout << s2.pop() << "  ";
	} while (!s2.isEmpty());
	cout << endl;
	system("pause");
	return 0;
}

1.8.jpg

友元函数

友元函数可以访问其他类中的私有成员,有助于数据共享,提高程序效率,但它又是对封装性的一个破坏,所以程序中不能大量使用友元

对友元函数的使用,和普通函数的使用方法一样,不需要在友元函数前面加上特殊标志。但是如果该友元函数是一个类的成员函数,则使用时还是要子啊友元函数前加上所属的类名。

#include <iostream>
using namespace std;
//对Date类的提前引用声明
class Date;
//定义Time类,声明display是其成员函数,形参是Date类对象的引用
class Time
{
public:
	Time(int, int, int);
	void display(Date &);
private:
	int hour, minute, sec;
};
//定义类Date,声明Time类中的display函数为本类的友元成员函数
class Date 
{
public:
	Date(int, int, int);
	friend void Time::display(Date&);
private:
	int month, day, year;

};
//定义Time的构造函数
Time::Time(int h, int m, int s) 
{
	hour = h;
	minute = m;
	sec = s;
}
//定义类Time的成员函数display时,引用了Date类对象中私有成员,也引用了本类对象中的私有数据
void Time::display(Date & da)
{
	cout << da.month << "/" << da.day << "/" << da.year << endl;
	cout << hour << ":" << minute << ":" << sec << endl;
}
//定义类Date的构造函数
Date::Date(int m, int d, int y)
{
	month = m;
	day = d;
	year = y;
}
int main()
{
	Time t1(19, 23, 45);
	Date d1(10, 9, 2020);
	//调用t1中的display函数,实参是Date类对象d1
	t1.display(d1);




	system("pause");
	return 0;
}

10.7.jpg

构造函数与析构函数

构造函数主要功能:
在创建对象的时候,给对象变量赋值。
析构函数主要功能:
当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数,在此对象撤销的时候释放所占用的资源

在建立一个类的对象时,首先调用构造函数对这个对象进行初始化。当这个对象的生命周期结束时,调用析构函数。

例如,定义了一个类,在该类的构造函数中申请了内存空间,在对该类实例的操作过程中应用内存空间进行操作,那么在该类的析构函数中,就要释放该内存空间。析构函数和构造函数相互呼应,完成内存空间的申请和释放。

#include <iostream>
using namespace std;

class People
{
public:
	People(){
		cout << "构造函数!" << endl;
	}
	~People() {
		cout << "析构函数!" << endl;
	}
};


void Method()
{
	People people;
	cout << "------------------" << endl;
}
int main()
{
	Method();




	system("pause");
	return 0;
}

11.2.2.jpg
在本例中,先输出了“构造函数”,说明首先调用了构造函数。接着输出“----------------------”,最后输出“析构函数”,说明在对象people的作用域结束后,才调用该对象的析构函数。

构造函数的重载

一个类可以有多个构造函数,这些构造函数有着不同的参数个数或者不同的参数类型,这些构造函数称为重载构造函数

使用不同的参数个数和参数类型对不同的对象进行初始化,实现类定义的多元性

#include <iostream>
using namespace std;

class Score
{
public:
	Score( float x1,float y1,float z1 );
	Score();
	void print();


private:
	float computer;
	float english;
	float math;
};
Score::Score(float x1, float y1, float z1) {//构造函数1
	computer = x1;
	english = y1;
	math = z1;
}
Score::Score() {//构造函数2
	computer = 0;
	english = 0;
	math = 0;
}
void Score::print() {
	cout << "计算机成绩为:\t" << computer
		<< "英语成绩为:\t" << english
		<< "数学成绩为:\t" << math
		<< endl;

}
int main()
{
	Score a;//调用构造函数2
	Score b(80, 90, 85);//调用构造函数1
	a.print();
	b.print();


	system("pause");
	return 0;
}

11.4.jpg

拷贝构造函数

拷贝构造函数实现了自己定义的类对象赋值给另一个对象

#include <iostream>
using namespace std;

class Test
{

public:
	int p1;
	Test(int temp)
	{
		p1 = temp;
	}
	//自定义的拷贝构造函数
	Test(Test& c_t)
	{
		cout << "进入copy构造函数" << endl;
		p1 = c_t.p1;
	}
};

int main()
{
	Test a(52014314);
	Test b = a;
	cout << b.p1;
	cout << endl;


	system("pause");
	return 0;
}

11.6.jpg

运算符的重载

C++通过运算符重载的操作赋予了运算符新的功能,使得预定义的运算符可以对我们自己定义的数据类型进行操作,扩展了运算符的功能

案例一:

#include <iostream>
using namespace std;
//定义com类,该类有两个成员real 和 img,重载运算符“+”
class com
{
private:
	int real, img;
public:
	com(int real = 0, int img = 0)
	{
		this->real = real;
		this->img = img;
	}
	//函数参数比原来的操作数少一个是因为:
	//this指针隐式的访问了类的一个对象,它充当了运算符函数最左边的操作数

	com operator + (com x)//当 com类 + com类时,执行(x1,y1) = (x1+x2,y1+y2)
	{
		return com(this->real + x.real, this->img + x.img);
	}

	com operator + (int x)//当 com类 + int数值时,执行(x1,y1) = (x1+x,y1)
	{
		return com(this->real + x, this->img);
	}
	//友元函数没有this指针,因此操作数的个数没有变化
	//所有的操作数都必须通过函数的形参进行传递,函数的参数与操作数自左至右一一对应

	friend com operator + (int x, com y)//当 int数值 +com类时,执行(x1,y1) = (x+x1,y1)
	{
		return com(x + y.real, y.img);
	}
	void show()
	{
		cout << real << "," << img << endl;
	}
};


int main()
{
	com a;
	com b(10, 10);
	com c(100, 100);

	a = b + c;// com类 + com类
	a.show();

	a = b + 1;//  com类 + int数值
	a.show();

	a = 1 + c;//  int数值 + com类
	a.show();


	system("pause");
	return 0;
}

12.1.jpg

案例二:

#include <iostream>
using namespace std;
//定义复数类CComplex.含有成员数据x、y,分别表示复数的实部和虚部;
//成员函数enterData(),show(),operator+()
class CComplex
{
private:
	double x, y;
public:
	void enterData()
	{
		cout << "输入一个复数(x ,y):";
		cin >> x >> y;
	}
	void show()
	{
		if (y >= 0) 
		{
			cout << "(" << x << "+" << y << "i)";
		}
		else
		{
			cout << "(" << x << y << "i)";
		}
	}
	//声明重载"+"运算符,成员函数operator+()
	CComplex operator + (CComplex z);
	//声明重载"!"运算符,成员函数operator!()
	CComplex operator !();
};
//在类外定义重载"+"运算符函数的实现,完成复数的加法运算
CComplex CComplex::operator + (CComplex z)
{
	CComplex t;
	t.x = x + z.x;
	t.y = y + z.y;

	return t;
}

//在类外定义重载"!"运算符函数的实现,完成复数的加法运算
CComplex CComplex::operator ! ()
{
	CComplex t;
	t.x = x;
	t.y = -y;
	return t;
}


int main()
{
	CComplex x1, x2, x3, u;
	x1.enterData();
	x2.enterData();
	x3.enterData();

	//利用重载运算符"+"完成复数运算
	u = x1 + x2 + x3;
	cout << "计算x1 + x2 + x3 = u的过程如下:" << endl;
	x1.show();cout << "+";
	x2.show();cout << "+";
	x3.show();cout << "=";
	u.show();cout << endl;

	cout << "u 的共轭复数为:" << endl;
	u = !u;
	u.show();cout << endl;


	system("pause");
	return 0;
}

12.1.2.jpg

运算符重载实现复数相关运算

设计一个复数类,可以实现有关复数操作,并应用该复数类求解一元二次方程的两个复根

complex.h

#include <iostream>
#include<math.h>
using namespace std;

class CComplex
{
private:
	double real, image;//复数的内部表示
public:
	//构造函数定义

	CComplex(void) { real = 0;image = 0; }//默认构造函数
	CComplex(double x) { real = x;image = 0; }//利用一个实数构造复数
	CComplex(double x, double y) { real = x;image = y; }//利用实部及虚部系数构造复数
	CComplex(const CComplex& z) //拷贝构造函数
	{
		real = z.real; image = z.image;
	}
	~CComplex(void) {}//析构函数

	//有关加减乘除运算的重载
	CComplex operator + (const CComplex& z) const;//两复数相加
	friend CComplex operator +(double x, const CComplex& z);//实数加复数
	CComplex operator -(const CComplex& z) const;//两复数相减
	friend CComplex operator -(double x, const CComplex& z);//实数减复数
	CComplex operator *(const CComplex& z) const;//两复数相乘
	friend CComplex operator *(double x, const CComplex& z);//实数乘复数
	CComplex operator /(const CComplex& z) const;//两复数相除
	friend CComplex operator /(double x, const CComplex& z);//实数除以复数




	//有关复合赋值运算的重载
	CComplex& operator =(const CComplex& z);
	CComplex& operator +=(const CComplex& z);
	CComplex& operator -=(const CComplex& z);
	CComplex& operator *=(const CComplex& z);
	CComplex& operator /=(const CComplex& z);

	int operator ==(const CComplex& z) const;//判断两个复数是否相等
	int operator !=(const CComplex& z) const;//判断两个复数是否不等
	CComplex operator!()const;//求共轭复数运算
	CComplex operator-()const;//求复数相反数运算

	void show()
	{
		cout << real;
		if (image >= 0)
		{
			cout << "+";
		}
		cout <<image<< "i";
	}

	//取模
	double getNorm()const
	{
		return sqrt(real * real + image * image);
	}

	//取幅角
	double getAngle()const;

	//取实部
	double getReal()const
	{
		return real;
	}
	//取虚部系数
	double getImage()const
	{
		return image;
	}
};

comple.app

#include"complex.h"
//两复数相加
CComplex CComplex::operator + (const CComplex& z) const
{
	CComplex tmp(real + z.real, image + z.image);
	return tmp;
}

//两复数相减
CComplex CComplex::operator - (const CComplex& z) const
{
	CComplex tmp(real - z.real, image - z.image);
	return tmp;
}

//两复数相乘
//(a+bi)∗(c+di)=(ac−bd)+(ad+bc)i
CComplex CComplex::operator * (const CComplex& z) const
{
	CComplex tmp(real * z.real - image * z.image, real * z.image + image * z.real);
	return tmp;
}

//两复数相除
//(a + bi) / (c + di) = (ac + bd) / (c2 + d2) + (bc − ad) / (c2 + d2)i 
CComplex CComplex::operator / (const CComplex& z) const
{
	CComplex tmp;
	tmp = *this * !z;
	double x = z.real * z.real + z.image * z.image;
	tmp.real /= x;
	tmp.image /= x;
	return tmp;
}
//实数加复数
CComplex operator +(double x, const CComplex& z) {
	CComplex tmp(x + z.real, z.image);
	return tmp;
 }

//实数减复数
CComplex operator -(double x, const CComplex& z) {
	CComplex tmp(x - z.real, -z.image);
	return tmp;
}

//实数乘复数
CComplex operator *(double x, const CComplex& z) {
	CComplex tmp(x * z.real, x*z.image);
	return tmp;
}

//实数除复数
CComplex operator /(double x, const CComplex& z) {
	CComplex tmp(x);
	return tmp/z;
}
//有关复数的复合赋值运算的实现
CComplex& CComplex::operator = (const CComplex& z)
{
	real = z.real;
	image = z.image;
	return *this;
}
CComplex& CComplex::operator += (const CComplex& z)
{
	real += z.real;
	image += z.image;
	return *this;
}
CComplex& CComplex::operator -= (const CComplex& z)
{
	real -= z.real;
	image -= z.image;
	return *this;
}
CComplex& CComplex::operator *= (const CComplex& z)
{
	*this = *this * z;
	return *this;
}
CComplex& CComplex::operator /= (const CComplex& z)
{
	*this = *this / z;
	return *this;
}
//有关复数的关系运算的实现
int CComplex::operator ==(const CComplex& z) const {
	return real == z.real && image == z.image;
}
int CComplex::operator !=(const CComplex& z) const {
	return *this==z;
}
//取共轭复数运算的实现
CComplex CComplex::operator !()const
{
	CComplex tmp(real, -image);
	return tmp;
}
//求复数相反数运算的实现
CComplex CComplex::operator -()const
{
	CComplex tmp(-real, -image);
	return tmp;
}

//取复数的幅角
double CComplex::getAngle()const
{
	const double PI = 3.1415926;
	double nrm = getNorm();
	if (nrm < 1e-6) return 0;
	double a = asin(fabs(image) / nrm);
	if (image > 0) 
	{
		if (real > 0) a = a;
		else a = PI - a;
	}
	else if (image < 0) 
	{
		if (real > 0) a = 2 * PI - a;
		else a = PI + a;
	}
	if (real > 0)  a = 0;
	else a = PI;

	return a;
}

main.cpp

#include"complex.h"
#include<math.h>
#include<iostream>
using namespace std;
//定义sqlt函数,计算复数的平方根
CComplex sqlt(const CComplex& z)
{
	double n = sqrt(z.getNorm()), angle = z.getAngle() / 2;
	CComplex d(n * cos(angle), n * sin(angle));
	return d;
}

int main()
{
	//ax^2+bx+c=0

	//求解x^2+x+3=0的根
	CComplex a(1), b(1), c(3), z1, z2, d;
	d = b * b - 4 * a * c;
	z1 = (-b + sqlt(d)) / (2 * a);
	z2= (-b - sqlt(d)) / (2 * a);

	cout << "z1=";z1.show();cout << endl;
	cout << "z2=";z2.show();cout << endl;

	system("pause");
	return 0;

}

12.2.jpg

运算符重载实现矩阵运算

rectangle.h

#include<iostream>
using namespace std;
class CRectangle
{
private:
	int row, col;//矩阵的行与列
	int* datas;//存储矩阵的数据
	static int dummy;//下标越界时的哑元素
	void init();
public:
	//定义空矩阵构造函数
	CRectangle()
	{
		row = 0;
		col = 0;
		datas = NULL;
		init();
	}
	//定义rowXcol矩阵构造函数
	CRectangle(int r,int c)
	{
		row = r;
		col = c;
		datas = new int[r * c];
		init();
	}
	//拷贝构造函数
	CRectangle(const CRectangle& a);
	//析构函数
	~CRectangle(){ delete datas; }
	//数与矩阵相乘
	friend CRectangle operator *(int x, const CRectangle& a);
	//取矩阵i,j位置处的元素
	int& operator ()(int i, int j);
	//将矩阵所有元素加1,前缀运算
	CRectangle operator ++();
	//将矩阵所有元素赋给另一个矩阵
	CRectangle& operator =(const CRectangle& a);
	//两矩阵相加
	CRectangle operator +(const CRectangle& a) const;
	//两矩阵相减
	CRectangle operator -(const CRectangle& a) const
	{
		return *this+ -a;
	}
	//两矩阵相乘
	CRectangle operator *(const CRectangle& a) const;
	//求转置矩阵
	CRectangle operator !() const;
	//-1与矩阵相乘
	CRectangle operator -() const
	{
		return  - (*this);
	}

	CRectangle operator +=(const CRectangle& a) ;
	CRectangle operator -=(const CRectangle& a)
	{
		return *this += -a;
	}
	CRectangle operator *=(const CRectangle& a);
	void show()const;
};

rectangle.cpp

#include "rectangle.h"
//拷贝构造函数的实现
CRectangle::CRectangle(const CRectangle& a)
{
	row = a.row;
	col = a.col;
	datas = new int[row * col];
	for (int i = 0;i < row * col;i++)
	{
		datas[i] = a.datas[i];//分配动态存储空间并赋初值
	}

}

//数与矩阵相乘
CRectangle operator *(int x, const CRectangle& a) 
{
	CRectangle tmp(a);
	for (int i = 0;i < a.row * a.row;i++)
	{
		tmp.datas[i] *= x;
	}
	return tmp;
}
//访问矩阵中的元素
int& CRectangle::operator()(int i, int j)
{
	if (i<1 || i>row || j<1 || j>col)
	{
		cout << "行列下标越界错误!" << endl;
		return dummy;
	}
	return datas[(i - 1) * col + j - 1];
}
//将矩阵所有元素加1,前缀运算
CRectangle  CRectangle::operator ++()
{
	CRectangle tmp(*this);
	for (int i = 0;i < row * col;i++)
	{
		tmp.datas[i]++;
	}
	return tmp;
}
//将矩阵所有元素赋给另一个矩阵
CRectangle& CRectangle::operator =(const CRectangle& a)
{
	delete datas;
	row = a.row;
	col = a.col;
	datas = new int[row * col];
	for (int i = 0;i < row * col;i++)
	{
		datas[i] = a.datas[i];
	}
	return *this;
}
//两矩阵相加
CRectangle CRectangle::operator +(const CRectangle& a) const
{
	if (row != a.row || col != a.col) 
	{
		CRectangle tmp;
		return tmp;
	}
	CRectangle tmp(*this);
	for (int i = 0;i < row * col;i++)
	{
		tmp.datas[i] += a.datas[i];
		return tmp;
	}
}
//两矩阵相乘
CRectangle CRectangle::operator *(const CRectangle& a) const
{
	if (col != a.row)
	{
		CRectangle tmp;
		return tmp;
	}
	CRectangle tmp(row, a.col);
	for (int i = 1;i <= row;i++)
	{
		for (int j = 1;j <= a.col;j++)
		{
			for (int k = 1;k <= col;k++)
			{
				tmp.datas[(i - 1) * tmp.col + j - 1] += 
			this->datas[(i - 1) * col + k - 1] * a.datas[(k - 1) * a.col + j - 1];
			}
		}
	}
	return tmp;
}
//求转置矩阵
CRectangle CRectangle::operator !() const
{
	CRectangle tmp(col, row);
	for (int i = 1;i <= row;i++)
	{
		for (int j = 1;j <= col;j++)
		{
			tmp.datas[(j - 1) * tmp.col + i - 1] = this->datas[(i - 1) * col + j - 1];
		}
	}
	return tmp;
}

CRectangle CRectangle::operator +=(const CRectangle& a)
{
	if (row != a.row || col != a.col)
	{
		CRectangle tmp;
		return tmp;
	}
	for (int i = 0;i < row * col;i++)
	{
		datas[i] += a.datas[i];
	}
	return *this;
}

CRectangle CRectangle::operator *=(const CRectangle& a)
{
	if (col != a.row)  return CRectangle();

	return *this = (*this) * a;
}

void CRectangle::show()const
{
	for (int i = 0;i < row;i++)
	{
		for (int j = 0;j < col;j++)
		{
			cout << datas[i * col + j]<<"   \t";
		}
		cout << endl;
	}
}
//初始化矩阵
void CRectangle::init()
{
	for (int i = 0;i < row * col;i++)
	{
		datas[i] = 0;
	}
}
//定义静态哑元素
int CRectangle::dummy;

main.cpp

#include"rectangle.h"
int main()
{
	CRectangle a(3, 3), b(3, 3), c;
	for (int i = 1;i <= 3;i++)
	{
		for (int j = 1;j <= 3;j++)
		{
			a(i, j) = i + 1;
			b(i, j) = j + 1;
		}
	}
	c = a * b;
	cout << "矩阵a为:" << endl;
	a.show();
	cout << "矩阵b为:" << endl;
	b.show();
	cout << "矩阵a*b为:" << endl;
	c.show();
	cout << "矩阵b的转置为:" << endl;
	(!b).show();
	cout << "矩阵-b为:" << endl;
	(-b).show();
	cout << "矩阵a各个元素加1为:" << endl;
	(++a).show();
	cout << "矩阵a各个元素乘3为:" << endl;
	(3*a).show();


	system("pause");
	return 0;
}

12.3.1.jpg

继承

  1. 公有继承 public
    基类的公有成员和保护成员在派生类中保持原有的访问属性,其私有成员仍为私有。
  2. 私有继承 private
    基类的公有成员和保护成员在派生类中成了私有成员,其私有成员仍为基类私有。
  3. 受保护的继承protected
    基类的公有成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。保护成员不能被外界引用,但可以被派生类的成员引用。
基类中的成员在public派生类中的访问属性在protected派生类中的访问属性在private派生类中的访问属性
私有成员不能访问不能访问不能访问
受保护成员受保护受保护私有
公有成员公有受保护私有
公有继承

基类的公有成员和保护成员在派生类中保持原有的访问属性,其私有成员仍为私有。

#include <iostream>
using namespace std;
class CBase
{
private:
	string name;
	int age;
public:
	string getName()
	{
		return name;
	}
	int getAge()
	{
		return age;
	}
protected:
	void setName(string s)
	{
		name = s;
	}
	void setAge(int i)
	{
		age = i;
	}

};
//用public指定公有继承
class CDerive : public CBase {
public:
	void setBase(string s, int i)
	{
		//调用基类的保护成员
		setName(s);
		setAge(i);
		//调用基类的私有成员
		//cout << name << " " << age << endl;   //编译错误
	}
};
int main()
{
	CDerive d;
	d.setBase("B.J.Han", 23);
	//调用基类的公有成员
	cout << d.getName() << "  " << d.getAge() << endl;

	//调用基类的私有成员
	//cout << d.name() << "  " << d.age() << endl;   //编译错误

	//调用基类的保护成员
	//d.setBase("xyz")   //编译错误
	system("pause");
	return 0;
}
/*
在本例中可以看出,在公有继承时:
	对于基类的私有成员,在派生类不可以访问	在外部不可以访问;
	对于基类的保护成员,在派生类可以访问	在外部不可以访问;
	对于基类的公有成员,在派生类可以访问	在外部可以访问;
*/

在这里插入图片描述

私有继承
#include <iostream>
using namespace std;
class CBase
{
private:
	string name;
	int age;
public:
	string getName()
	{
		return name;
	}
	int getAge()
	{
		return age;
	}
protected:
	void setName(string s)
	{
		name = s;
	}
	void setAge(int i)
	{
		age = i;
	}

};
//用private指定私有继承
class CDerive : private CBase {
public:
	void setBase(string s, int i)
	{
		//调用基类的保护成员
		setName(s);
		setAge(i);
		//调用基类的私有成员
		//cout << name << " " << age << endl;   //编译错误
	}
	//调用基类的公有成员
	string getBaseName()
	{
		return getName();
	}
	int getBaseAge()
	{
		return getAge();
	}
};
int main()
{
	CDerive d;
	d.setBase("B.J.Han", 23);
	//调用基类的公有成员
	//cout << d.getName() << "  " << d.getAge() << endl;   //编译错误
	//调用基类的私有成员
	//cout << d.name << endl;   //编译错误
	//调用基类的保护成员
	//d.setName("dad");   //编译错误


	cout << d.getBaseName() << "  " << d.getBaseAge() << endl;
	system("pause");
	return 0;
}
/*
在本例中可以看出,在私有继承时:
	对于基类的私有成员,在派生类不可以访问	在外部不可以访问;
	对于基类的保护成员,在派生类可以访问	在外部不可以访问;
	对于基类的公有成员,在派生类可以访问	在外部不可以访问;
*/

在这里插入图片描述

保护继承
#include <iostream>
using namespace std;
class CBase
{
private:
	string name;
	int age;
public:
	string getName()
	{
		return name;
	}
	int getAge()
	{
		return age;
	}
protected:
	void setName(string s)
	{
		name = s;
	}
	void setAge(int i)
	{
		age = i;
	}

};
//用protected指定保护继承
class CDerive : protected CBase {
public:
	void setBase(string s, int i)
	{
		//调用基类的保护成员
		setName(s);
		setAge(i);
		//调用基类的私有成员
		//cout << name << " " << age << endl;   //编译错误
	}
	//调用基类的公有成员
	string getBaseName()
	{
		return getName();
	}
	int getBaseAge()
	{
		return getAge();
	}
};
int main()
{
	CDerive d;
	d.setBase("B.J.Han", 23);
	//调用基类的公有成员
	//cout << d.getName() << "  " << d.getAge() << endl;   //编译错误
	//调用基类的私有成员
	//cout << d.name << endl;   //编译错误
	//调用基类的保护成员
	//d.setName("dad");   //编译错误


	cout << d.getBaseName() << "  " << d.getBaseAge() << endl;
	system("pause");
	return 0;
}
/*
在本例中可以看出,在保护继承时:
	对于基类的私有成员,在派生类不可以访问	在外部不可以访问;
	对于基类的保护成员,在派生类可以访问	在外部不可以访问;
	对于基类的公有成员,在派生类可以访问	在外部不可以访问;
*/

在这里插入图片描述

调用父类的构造函数

构造函数不能被继承类继承,因此在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法

默认调用父类构造函数
#include <iostream>
using namespace std;

class Animal
{
public:
	void eat()
	{
		cout << "animal eat" << endl;
	}
	void sleep()
	{
		cout << "animal sleep" << endl;
	}
	void breathe()
	{
		cout << "animal breathe" << endl;
	}
	//类animal的构造函数
	Animal()
	{
		cout << "animal construct" << endl;
	}
};
class Fish :public Animal 
{
public:
	//类Fish的构造函数
	Fish() 
	{
		cout << "fish construct" << endl;
	}
};
int main()
{
	Fish smallFish;
	smallFish.breathe();
	smallFish.eat();
	smallFish.sleep();




	system("pause");
	return 0;
}

在这里插入图片描述

从本例的运行结果可以看出,在调用子类的构造函数前先调用了父类的构造函数,即是没有显式地在定义子类构造函数时调用父类的构造函数,C++已经自己调用了

调用父类带参构造函数
#include <iostream>
using namespace std;
//基类
class Document
{
public:
	Document(string D_newName);
	void getName();
	string D_Name;
};

Document::Document(string D_newName)
{
	D_Name = D_newName;
	cout << "父类构造函数调用!" << endl;
}
void Document::getName()
{
	cout << "Document类的名字是:" << D_Name << endl;
}
//派生类
class Book :public Document
{
public:
	Book(string D_newName, string newName);
	void getName();
	void setPageCount(int newPageCount);
	void getPageCount();
private:
	int PageCount;
	string Name;
};

Book::Book(string D_newName, string newName) :Document(D_newName)
{
	Name = newName;
	cout << "子类构造函数调用!" << endl;
}
void Book::getName()
{
	cout << "Book类的名字是:" << Name << endl;
}
void Book::setPageCount(int newPageCount)
{
	PageCount = newPageCount;
}
void Book::getPageCount()
{
	cout << "Book类的页数是:" << PageCount << endl;
}
int main()
{
	Book x("计算机教材", "C++从零开始学");
	x.getName();
	x.setPageCount(380);
	x.getPageCount();

	system("pause");
	return 0;
}

在这里插入图片描述

从本例的运行结果可以看出,在调用子类的构造函数之前先调用了父类的构造函数,并且将子类的参数传递给了父类的构造函数。

继承与静态成员
#include <iostream>
using namespace std;
class A
{
public:
	static int a, b, c;
};
int A::a = 100;
int A::b = 200;
int A::c = 300;

class B :public A
{
public:
	void out()
	{
		cout << a << "  " << b << "  " << c << endl;
	}
	void plus()
	{
		++a;
		++b;
		c++;
	}
};
int main()
{
	A a1;
	B b1;
	b1.plus();
	b1.out();
	cout << "-------------------" << endl;
	cout << a1.a << "  " << a1.b << "  " << a1.c << endl;



	system("pause");
	return 0;
}

在这里插入图片描述

在本例中可以看出,在子类中对父类定义的静态函数进行访问和数据修改,从而知道,父类中的静态成员是可以访问的。

多继承

一个派生类可能有两个或者多个基类,派生类从两个或多个基类中继承所需的属性。

#include <iostream>
using namespace std;
class B1
{
public:
	B1(int i)
	{
		b1 = i;
		cout << "构造函数B1." << endl;
	}
	void print()
	{
		cout << b1 << endl;
	}
private:
	int b1;
};
class B2
{
public:
	B2(int i)
	{
		b2 = i;
		cout << "构造函数B2." << endl;
	}
	void print()
	{
		cout << b2 << endl;
	}
private:
	int b2;
};
class B3
{
public:
	B3(int i)
	{
		b3 = i;
		cout << "构造函数B3." << endl;
	}
	void print()
	{
		cout << b3 << endl;
	}
	int getb3() {
		return b3;
	}
private:
	int b3;
};
class A :public B2, public B1
{
private:
	int a;
	B3 bb;
public:
	A(int i, int j, int k, int l) :B1(i), B2(j), bb(k)
	{
		a = l;
		cout << "构造函数A." << endl;
	}
	void print()
	{
		B1::print();
		B2::print();
		bb.print();
		cout << a << endl;
	}
};
int main()
{
	A aa(100, 200, 300, 400);
	aa.print();

	system("pause");
	return 0;
}
/*
从本例的结果可以看出,调用了各个父类的构造函数,构造函数调用的顺序为声明派生类时基类出现的顺序
*/

在这里插入图片描述

案例二:

#include <iostream>
#include<string>
using namespace std;
//声明教师类Teacher
class Teacher
{
protected:
	string t_name;
	int age;
	string title;
public:
	//构造函数
	Teacher(string nam, int a, string t)
	{
		t_name = nam;
		age = a;
		title = t;
	}
	void t_display()
	{
		cout << "name:" << t_name << endl;
		cout << "age:" << age << endl;
		cout << "title:" << title << endl;
	}
};
//定义学生类
class Student
{
protected:
	string s_name;
	char sex;
	float score;
public:
	//构造函数
	Student(string nam, char s, float sco)
	{
		s_name = nam;
		sex = s;
		score = sco;
	}
	void s_display()
	{
		cout << "name:" << s_name << endl;
		cout << "sex:" << sex << endl;
		cout << "score:" << score << endl;
	}
};
//声明多重继承的派生类Graduate
class Graduate :public Teacher, public Student
{
private:
	float wage;//工资
public:
	//派生类构造函数,并且完成新增成员的初始化
	Graduate(string nam, int a, char s, string t, float sco, float w) :
		Teacher(nam, a, t), Student(nam, s, sco)
	{
		wage = w;
	}
	//派生类成员函数。输出研究生的有关数据
	void show()
	{
		cout << "name:" << t_name << endl;
		cout << "age:" << age << endl;
		cout << "sex:" << sex << endl;
		cout << "score:" << score << endl;
		cout << "title:" << title << endl;
		cout << "wage:" << wage << endl;
	}
};
int main()
{
	Graduate grad1("韩宝建", 23, 'F', "assistant", 89.5, 12000);
	grad1.show();

	system("pause");
	return 0;
}

在这里插入图片描述
案例三:

#include <iostream>
using namespace std;
//定义人员类
class person
{
public:
	//输入编号和姓名
	void getdata()
	{
		cout << "编号:" ;
		cin >> no;
		cout << "姓名:";
		cin >> name;

	}
	//输出编号和姓名
	void dispdata()
	{
		cout << "编号:" << no << endl;
		cout << "姓名:" << name << endl;
	}
protected:
	int no;
	char name[8];
};
//定义教师类teacher,公有继承person
class teacher :public person
{
public:
	void getdata()
	{
		cout << "请输入一个教师数据:" << endl;
		person::getdata();
		cout << "职称:";
		cin >> prof;
		cout << "教研室:";
		cin >> depart;
	}
	void dispdata()
	{
		cout << "输出一个教师数据:" << endl;
		person::dispdata();
		cout << "职称:" << prof << endl;
		cout << "教研室:" << depart << endl;
	}
protected:
	char prof[10];//职称
	char depart[10];//教研室

};
//定义学生类student,公有继承person类
class student :public person
{
public:
	void getdata()
	{
		person::getdata();
		cout << "性别:";
		cin >> sex;
		cout << "班号:";
		cin >> cname;
	}
	void dispdata()
	{
		person::dispdata();
		cout << "性别:" << sex << endl;
		cout << "班号:" << cname << endl;
	}
protected:
	char sex[4];
	char cname[10];
};
//定义大学生类unstudent,公有继承student类
class unstudent :public student
{
private:
	int degree1;//英语
	int degree2;//高数
	int degree3;//数据结构
public:
	void getdata()
	{
		cout << "请输入一个大学生数据:" << endl;
		student::getdata();
		cout << "英语:";
		cin >> degree1;
		cout << "高等数学:";
		cin >> degree2;
		cout << "数据结构:";
		cin >> degree3;
	}
	void dispdata()
	{
		cout << "输出一个大学生数据" << endl;
		student::dispdata();
		cout << "英语:" << degree1 << endl;
		cout << "高等数学:" << degree2 << endl;
		cout << "数据结构:" << degree3 << endl;
		cout << "平均分:" << (degree1 + degree2 + degree3) / 3 << endl;
	}
};
int main()
{
	teacher t;
	t.getdata();
	unstudent s;
	s.getdata();
	cout << "---------打印信息---------" << endl;
	t.dispdata();
	s.dispdata();




	system("pause");
	return 0;
}

在这里插入图片描述
案例四:

#include <iostream>
using namespace std;
//汽车类vehicle
class vehicle
{
public:
	vehicle(int whels, float wht);
	int getwheels();
	float getweight();
	void print();
protected:
	int wheels;//车轮
	float weight;//重量
};
//定义轿车类car,私有继承汽车类vehicle
class car :private vehicle
{
public:
	car(int wheels, float wht, int passengers) :vehicle(wheels, wht)
	{
		passengerload = passengers;
	}
	int getpassengers();
	void print();
private:
	int passengerload;

};
//定义卡车类truck,私有继承汽车类vechicle
class truck :private vehicle
{
public:
	truck(int wheels, float wht, int passengers, float maxlod) :vehicle(wheels, wht)
	{
		passengerload = passengers;
		payload = maxlod;
	}
	int getpassengers();
	float efficiency();
	void print();
private:
	int passengerload;
	float payload;
};
vehicle::vehicle(int whels, float wht)
{
	wheels = whels;
	weight = wht;
}
int vehicle::getwheels()
{
	return wheels;
}
float  vehicle::getweight()
{
	return weight;
}
void vehicle::print()
{
	cout << "车轮:" << wheels << "个" << endl;
	cout << "重量:" << weight << "公斤" << endl;
}
int car::getpassengers()
{
	return passengerload;
}
void car::print()
{
	cout << "轿车:" << endl;
	vehicle::print();
	cout << "载:" << passengerload << "人" << endl;
	cout << "-------------------"<<endl;
}
int truck::getpassengers()
{
	return passengerload;
}
float truck::efficiency()
{
	return payload/(payload+weight);
}
void truck::print()
{
	cout << "卡车:" << endl;
	vehicle::print();
	cout << "载:" << passengerload << "人" << endl;
	cout << "效率:" << efficiency();
	cout << endl;
}
int main()
{
	car c1(4, 1000, 5);
	truck t1(6, 5000, 3, 3400);
	c1.print();
	t1.print();

	system("pause");
	return 0;
}

在这里插入图片描述

虚函数

虚函数的定义

虚函数是C++实现多态性的主要手段之一。

对于发送消息的类的对象来说,不论它们属于什么类,发送的消息形式都一样,而对于处理信息的类的对象对同一信息反应不同称为多态性。

在基类中定义一个虚函数,其派生类继承该基类的虚函数,并且实现该函数。对于不同派生类的对象接受同一个信息,调用相同的函数名,操作不同。

#include <iostream>
using namespace std;
class base
{
public:
	virtual void vfunc()
	{
		cout << "This is base's vfunc()" << endl;
	}
};
class derived1 :public base
{
public:
	void vfunc()
	{
		cout << "This is derived1's vfunc()" << endl;
	}
};
class derived2 :public base
{
public:
	void vfunc()
	{
		cout << "This is dervied2's vfunc()" << endl;
	}
};
int main()
{
	base* p, d;
	derived1 d1;
	derived2 d2;
	p = &d;
	p->vfunc();

	p = &d1;
	p->vfunc();

	p = &d2;
	p->vfunc();
	cout << "-------------------------" << endl;
	d.vfunc();
	d1.vfunc();
	d2.vfunc();

	system("pause");
	return 0;
}

在这里插入图片描述

动态绑定和静态绑定

静态绑定的是对象的静态类型,在编译是绑定,然后通过对象来调用。
动态绑定的是对象的动态类型,在运行时绑定,然后通过地址来实现。

只有采用“指针->函数()”或“引用变量.函数()”的方式调用C++类中的虚函数才会执行动态绑定。

#include <iostream>
using namespace std;

class CBase
{
public:
	virtual int func() const
	{
		cout << "CBase function!" << endl;
		return 100;
	}
};

class CDerive :public CBase
{
public:
	int func() const
	{
		cout << "CDerive function!" << endl;
		return 200;
	}
};

int main()
{
	CDerive obj1;
	CBase* p1 = &obj1;//指针
	CBase& p2 = obj1;//引用变量
	CBase obj2;
	//静态绑定:调用对象本身(派生类CDerive对象)的func函数
	obj1.func();

	//动态绑定:调用被引用对象所属类(派生类CDerive)的func函数
	p1->func();//指针->函数()

	//动态绑定:调用被引用对象所属类(派生类CDerive)的func函数
	p2.func();//引用变量.函数()

	//静态绑定:调用对象本身(派生类CBase对象)的func函数
	obj2.func();

	system("pause");
	return 0;
}

在这里插入图片描述

抽象类和纯虚函数

在基类中不能对虚函数给出有意义的实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。

带有纯虚函数的类称为抽象类。

纯虚函数:

#include <iostream>
using namespace std;

class shape
{
public:
	shape() {};
	virtual void draw() = 0;//纯虚函数
};
class rectangle :public shape
{
public:
	rectangle() {};
	void draw()
	{
		cout << "绘制一个矩形!" << endl;
	}
};
class round1 :public shape
{
public:
	round1() {};
	void draw()
	{
		cout << "绘制一个圆!" << endl;
	}
};
int main()
{
	shape* s;//基类指针对象
	s = new rectangle();
	s->draw();
	s = new round1();
	s->draw();


	system("pause");
	return 0;
}

在这里插入图片描述
抽象类的作用:
一个抽象类是不能定义对象的,只能作为基类来被继承,由它作为一个公共的接口,每个派生类都是从这个公共接口派生出来的。

#include <iostream>
using namespace std;

class Base
{
public:
	Base() { cout << "Base的构造函数!" << endl; };
	virtual ~Base() { cout << "Base的析构函数!" << endl; };
	virtual void HBJ() = 0;
};
class CBase :public Base
{
public:
	CBase() :Base() { cout << "CBase的构造函数!" << endl; };
	~CBase() { cout << "CBase的析构函数!" << endl; };
	void HBJ()
	{
		cout << "HBJ大帅比!" << endl;
	}
};
void H()
{
	CBase h;
	h.HBJ();
	cout << "---" << endl;
}
int main()
{

	H();

	system("pause");
	return 0;
}

在这里插入图片描述

抽象类的多重继承

一个派生类可以有多个基类,这样的继承机构称为多重继承。
子类多重继承了抽象类,并且实现了每个基类的纯虚函数。

#include <iostream>
using namespace std;

class AbstractClass
{
public:
	AbstractClass() {};
	virtual ~AbstractClass() {};
	virtual void toString() = 0;
};
class BbstractClass
{
public:
	BbstractClass() {};
	virtual ~BbstractClass() {};
	virtual void toDouble() = 0;
};
class SubClass :public AbstractClass, public BbstractClass
{
public:
	SubClass() :AbstractClass(), BbstractClass() {};
	~SubClass() {};
	void toString()
	{
		cout << "Sub::toString()"<<endl;
	}
	void toDouble()
	{
		cout << "Sub::Double()\n";
	}
};
int main()
{
	SubClass s;

	s.toString();

	s.toDouble();

	system("pause");
	return 0;
}

在这里插入图片描述

文件处理

案例一(fstream):

#include <iostream>
#include<fstream>
using namespace std;

int main()
{
	char buffer[256];
	fstream out;
	//ios::in表示以只读的方式读取文件
	out.open("1.txt", ios::in);
	cout << "1.txt" << "的内容如下:" << endl;
	while (!out.eof())
	{
		//getline(char *,int,char)表示该行字符达到256个或者遇到换行符就结束
		out.getline(buffer, 256, '\n');
		cout << buffer << endl;
	}
	out.close();
	//cin.get()是用来读取回车键的,如果没有这一行,输出结果一闪就消失了
	cin.get();
	system("pause");
	return 0;
}

1.txt

1 无花无酒过清明
2 兴味萧然似野僧
3 昨日邻家乞新火
4 晓窗分与读书灯

在这里插入图片描述
案例二(ifstream):

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int CountLines(const char* filename)
{
	ifstream ReadFile;
	int n = 0;
	char line[512];
	string temp;
	ReadFile.open(filename, ios::in);
	//文件打开失败,返回
	if (ReadFile.fail())
	{
		return 0;
	}
	else
	{
		//getline (istream &  is, string& str, char delim);
		//is:表示一个输入流,例如 cin。
		//str:用来存储输入流中的信息
		//delim:自定义结束字符,默认是  '\n '
		while (getline(ReadFile, temp))
		{
			n++;
		}
		return n;
	}
	ReadFile.close();
}
int main()
{

	cout << "1.txt的行数为:" << CountLines("1.txt") << endl;

	system("pause");
	return 0;
}

在这里插入图片描述
案例三(ofstream):

#include <iostream>
#include<fstream>
using namespace std;

int main()
{
	ofstream in;
	//ios::trunc表示再打开文件前将文件清空,由于是写入,
	//因此,若文件不存在,侧创建文件
	in.open("com.txt", ios::trunc);
	int i;
	char a = 'a';
	for (i = 1;i < 27;i++)
	{
		if (i < 10)
		{
			in << "0"<<i << "\t" << a << "\n";
			a++;
		}
		else
		{
			in << i << "\t" << a << "\n";
			a++;
		}
	}
	in.close();

	system("pause");
	return 0;
}

在这里插入图片描述
案例四(随机文件读写):

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int CountLines(char* filename)
{
	ifstream ReadFile;
	int n = 0;
	string tmp;
	ReadFile.open(filename, ios::in);
	//文件打开失败,返回
	if (ReadFile.fail())
	{
		return 0;
	}
	else
	{
		while (getline(ReadFile, tmp))
		{
			n++;
		}
		return n;
	}
	ReadFile.close();
}
string ReadLine(char* filename, int line)
{
	int lines, i = 0;
	string temp;
	fstream file;
	//只读方式打开
	file.open(filename, ios::in);
	lines = CountLines(filename);
	if (line < 0)
	{
		return  "Error 1:行数错误,不能为0或负数" ;
	}
	if (file.fail())
	{
		return "Error 2:文件不存在";
	}
	if (line > lines)
	{
		return "Error 3:行数超出文件长度";
	}
	while (getline(file, temp) && i < line - 1)
	{
		i++;
	}
	file.close();
	return temp;
}
int main()
{

	int l;
	char filename[256];
	cout << "请输入文件名:" << endl;
	cin >> filename;
	cout << "请输入要读取的行数:" << endl;
	cin >> l;
	cout << ReadLine(filename, l);
	cin.get();

	cout << endl;
	system("pause");
	return 0;
}

在这里插入图片描述

文件的打开与关闭

在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
void open(const char* filename,int mode,int access);

  • filename:要打开的文件名
  • mode:要打开文件的方式
  • access:打开文件的属性

打开文件的方式在类ios中定义,常用值如下:

  • ios;;app 已追加的方式打开文件
  • ios::ate 打开文件后定位到文件尾,ios::app就包含此属性
  • ios::binary 以二进制的方式打开文件,默认的方式是文本方式
  • ios::in 文件以输入方式打开(文件数据输入到内存)
  • ios::out 文件以输出方式打开(内存数据输出到文件)
  • ios::nocreate 不建立文件,所以文件不存在时打开失败
  • ios::noreplace 不覆盖文件,所以文件存在时打开失败
  • ios::trunc 如果文件存在,就把文件长度设为0

可以用“或”把以上属性连接起来,如 ios::out|ios::binary
打开文件的属性取值有以下几种:

  • 0:普通文件,打开访问
  • 1:只读文件
  • 2:隐含文件
  • 3:系统文件

文件关闭:
void close ();

文本文件用运算符(<<)向文件输出,用析取运算符(>>)从文件输入

异常处理的概念

在进行团队开发的过程中,可以通过对异常处理机制来降低产生错误的可能性,从而提高程序的可靠性。

仅仅用if语句的判断,并不能够将所有出现异常的可能性都包括,如果开发较大规模的程序,就会导致正常的逻辑代码和处理异常的代码混淆在一起,增加了程序维护的难度。

通过异常处理机制,在整个程序段发生异常后都不至于导致程序出错,而是将异常抛出。
案例一(除数为0):

#include <iostream>
using namespace std;

double fuc(double x, double y)
{
	if (y == 0)
	{
		throw y;//除数为0,抛出异常
	}
	return x / y;
}

int main()
{
	double res;
	//定义异常
	try
	{
		res = fuc(100 ,60);
		cout << "100/60的结果为:" << res << endl;
		res = fuc(100 , 0);
	}
	//捕获并处理异常
	catch (double)
	{
		cerr << "Error of dividing zero." << endl;
	}

	system("pause");
	return 0;
}

在这里插入图片描述
结果分析:
该例中,除数为0的异常,用throw语句来抛出异常,用try/catch语句来捕获,从而实现异常处理。

案例二(方程无实数根):

#include <iostream>
#include<math.h>
using namespace std;

double sqrt_delta(double d)
{
	if (d < 0)
	{
		throw 1;
	}
	return sqrt(d);
}
double delta(double a, double b, double c)
{
	double d = b * b - 4 * a * c;
	return sqrt_delta(d);
}


int main()
{
	double a, b, c;
	cout << "请输入a,b,c的值:" << endl;
	cin >> a >> b >> c;
	while (true)
	{
		try
		{
			double d = delta(a, b, c);
			cout << "x1:" << (d - b) / (2 * a)  << endl;
			cout << "x1:" << -(d + b) / (2 * a) << endl;
			break;
		}
		catch (int)
		{
			cout << "delta < 0,请重新输入a,b,c:";
			cin >> a >> b >> c;
		}
	}


	system("pause");
	return 0;
}

在这里插入图片描述
案例三(捕获多个异常):

#include <iostream>
using namespace std;

void fun(int x)
{
	try 
	{
		if (x == 1) throw 1;
		if (x == 2) throw 1.0;
		if (x == 3) throw 1;
	}
	catch (int)
	{
		cout << "catch an int in fun()" << endl;
	}
	catch (double)
	{
		cout << "catch an double in fun()" << endl;
	}
	cout << "texting exception in fun()" << endl;
}
void gun()
{
	try 
	{
		fun(1);
		//fun(2);
		//fun(3);
		//fun(4);
	}
	catch (char)
	{
		cout << "catch a char in gun()" << endl;
	}
	cout << "texting exception in gun()" << endl;
}
int main()
{
	gun();
	
	system("pause");
	return 0;
}

在这里插入图片描述

模板

模板的作用是实现代码的重用,它通过将某一种数据类型定义为参数,然后通过将不同的数据类型按照实参形式传送而实现代码重用。
案例一(将两个同类型的较小值输出):

#include <iostream>
using std::cout;
using std::endl;
//声明函数模板,用来比较两个相同数据类型的参数大小
//class可以被typename代替
//T可以被任何字母或数字代替
template<class T>
T min(T x, T y)
{
	return (x < y) ? x : y;
}
int main()
{
	int n1 = 188, n2 = 269;
	double d1 = 3.6, d2 = 6.8;
	cout << "较小整数:" << min(n1, n2) << endl;
	cout << "较小实数:" << min(d1, d2) << endl;

	system("pause");
	return 0;
}

在这里插入图片描述
案例二(类模板):

#include <iostream>
using std::cout;
using std::endl;

class A
{
public:
	A(int i)
	{
		m_A = i;
	}
	~A(){}
	static void print()
	{
		std::cout << "A" << std::endl;
	}
	friend class B;
protected:
	int m_A;
};
class B
{
public:
	B(int i)
	{
		m_B = i;
	}
	static void print()
	{
		std::cout << "B"<<std::endl;
	}
	void show(B b)
	{
		b.a->m_A = 3;
		b.m_B = 2;
	}
private:
	A* a;
	int m_B;
};
template<class T1,class T2>
class CTestTemplate
{
public:
	CTestTemplate(T1 t)
	{
		m_number = t;
	}
	void print()
	{
		T2::print();
		std::cout << m_number << std::endl;
	}
private:
	T1 m_number;
};
int main()
{
	CTestTemplate<int, B>testtem(3);
	testtem.print();
	system("pause");
	return 0;
}

在这里插入图片描述
定义A类,在类中定义构造函数和析构函数,并且定义一个输出函数,将A类中的成员变量输出。接下来定义了一个与A类类似的B类,输出B类的成员内容。
然后,定义了一个类模板,又定义了类模板CTestTemplate,在该类分别对其中的类成员T1和T2进行了操作,将T1赋值给了该类的成员变量,调用T2的输出函数。



C++易混概念

const 修饰符

const修饰符的作用是修饰一个不能被更新的参数。
程序一:

#include <iostream>
using namespace std;
int main()
{
	int i;
	i = 1;
	cout<< i <<endl;
	system("pause");
	return 0;
}

输出结果:
在这里插入图片描述
程序二:

#include <iostream>
using namespace std;
int main()
{
	 const int i;
	 i = 1;
	cout<< i <<endl;
	system("pause");
	return 0;
}

报错:
在这里插入图片描述
这说明:
1.被const修饰的对象如果不是在函数体外部定义,则必须进行初始化。
2.被const修饰对象不能在程序中修改。
因此被const修饰的对象是不能被改变的常量对象,也叫常类型。

当一个函数使用指针类型或引用参数类型时,函数体中可以对指针指向的对象或引用的对象进行间接修改,为避免被引用的对象或被指向的对象被间接修改,可将其声明为const类型指针或const类型引用。

“&”引用运算符

在拷贝构造函数CMyString(const CMstring &s)中,&s叫做对象引用。“&”被叫做引用运算符(并非取地址运算符)。此时,对象引用作为函数的形参。
在C++中引用作为形参的一般用法格式:

形参说明格式为:type1 &a
对应实参的格式为:b

其中,a前面的type1是引用的对象类型,同时也是实参b的类型。形实结合时,建立a和b之间的“引用”关系(a是b的引用,a是b的别名),在被调函数体内,a就等于b。对a的赋值实际上就是对b的赋值,所以可以通过引用带回计算结果。

new和delete

new和delete是动态存储空间分配和释放的运算符。
(1)new动态分配存储空间
str = new char[len+1]语句的作用是:str被设置为指向被动态分配的字符串存储空间的指针。
(2)delete释放存储空间
在析构函数~CMyString(){if (len) delete str;}中,delete str 的作用就是释放字符串存储空间。



案例实现

通讯录实现

通讯录是一个可以记录亲人、好友信息的工具。

本教程主要利用C++来实现一个通讯录管理系统

系统中需要实现的功能如下:

  • 添加联系人:向通讯录中添加新人,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人
  • 显示联系人:显示通讯录中所有联系人信息
  • 删除联系人:按照姓名进行删除指定联系人
  • 查找联系人:按照姓名查看指定联系人信息
  • 修改联系人:按照姓名重新修改指定联系人
  • 清空联系人:清空通讯录中所有信息
  • 退出通讯录:退出当前使用的通讯录

代码实现

#include <iostream>
using namespace std;
#define MAX 1000
//联系人结构体
struct Person {
	//姓名
	string m_Name;
	//性别  1-男  2-女
	int m_Sex;
	//年龄
	int m_Age;
	//电话
	string m_Phone;
	//住址
	string m_Addr;
};
//通讯录结构体
struct Addressbooks {
	//通讯录中保存的联系人数组
	struct Person personArray[MAX];
	//通讯录中当前记录联系人个数
	int m_Size;
};


//添加联系人
void addPerson(Addressbooks * abs) {
	//判断通讯录是否已满,如果满了就不再添加
	if (abs->m_Size == MAX) {
		cout << "通讯录已经满了,无法添加!" << endl;
		return;
	}
	else {

		//添加联系人

		//姓名
		string name;
		cout << "请输入姓名:" << endl;
		cin >> name;
		abs->personArray[abs->m_Size].m_Name = name;
		//性别
		cout << "请输入性别:" << endl;
		cout << "1---- 男" << endl;
		cout << "2---- 女" << endl;
		int sex = 0;
		while (true) {
			cin >> sex;
			if (sex == 1 || sex == 2) {
				abs->personArray[abs->m_Size].m_Sex = sex;
				break;
			}
			
			cout << "输入有误,请重新输入" << endl;

			

		}
		
		//年龄
		cout << "请输入年龄:" << endl;
		int age = 0;
		while (true) {
			cin >> age;
			if (age < 150|| age >10) {
				abs->personArray[abs->m_Size].m_Age = age;
				break;
			}
			cout << "输入有误,请重新输入" << endl;
			
		}

		//电话
		cout << "请输入联系电话:" << endl;
		string phone;
		cin >> phone;
		abs->personArray[abs->m_Size].m_Phone = phone;

		//住址
		cout << "请输入家庭住址:" << endl;
		string address;
		cin >> address;
		abs->personArray[abs->m_Size].m_Addr = address;


		abs->m_Size++;
		cout << "添加成功!" << endl;
		
		system("pause");//按任意键继续
		system("cls");//清屏

	}
}
//显示所有联系人
void showPerson(Addressbooks* abs) {
	if (abs->m_Size == 0) {
		cout << "当前记录为空" << endl;
	}
	else {
		for (int i = 0;i < abs->m_Size;i++) {
			cout << "姓名:" << abs->personArray[i].m_Name<<" ";
			cout << "性别:" << (abs->personArray[i].m_Sex == 1 ? "男":"女") << " ";
			cout << "年龄:" << abs->personArray[i].m_Age << " ";
			cout << "电话:" << abs->personArray[i].m_Phone << " ";
			cout << "住址:" << abs->personArray[i].m_Addr
				 << endl;
		}
	}
	system("pause");
	system("cls");
}
//检测联系人是否存在,如果存在,返回联系人所在数组在的具体位置,不存在返回-1
int isExist(Addressbooks* abs, string name) {
	for (int i = 0;i < abs->m_Size;i++) {
		if (abs->personArray[i].m_Name == name)
		{
			return i;//找到了,返回这个人在数组的下标
		}

	}
	return -1;//找不到
}
//删除指定联系人
void deletePerson(Addressbooks* abs) {
	cout << "请输入您要删除的联系人:" << endl;
	string name;
	cin >> name;

	int ret = isExist(abs, name);
	if (ret != -1) {
		//找到此人,进行删除
		for (int i = ret;i < abs->m_Size;i++) {
			abs->personArray[i] = abs->personArray[i + 1];
		}
		abs->m_Size--;
		cout << "删除成功!" << endl;
	}
	else {
		//查无此人
		cout << "查无此人!" << endl;
	}
	system("pause");
	system("cls");
}
//查找指定联系人信息
void findPerson(Addressbooks* abs) {
	cout << "请输入您要查找的联系人:" << endl;
	string name;
	cin >> name;

	int ret = isExist(abs, name);
	if (ret != -1) {
		cout << "姓名:" << abs->personArray[ret].m_Name << "\t";
		cout << "性别:" << abs->personArray[ret].m_Sex << "\t";
		cout << "年龄:" << abs->personArray[ret].m_Age << "\t";
		cout << "电话:" << abs->personArray[ret].m_Phone << "\t";
		cout << "住址:" << abs->personArray[ret].m_Addr << "\t"
		<< endl;

	}
	else {
		cout << "查无此人" << endl;
	}
	system("pause");
	system("cls");
}
//修改指定联系人的信息
void modifyPerson(Addressbooks* abs) {

	cout << "请输入您要修改的联系人:" << endl;
	string name;
	cin >> name;
	int ret = isExist(abs, name);

	if (ret != -1) {

		string name;
		cout << "请输入姓名:" << endl;
		cin >> name;
		abs->personArray[ret].m_Name = name;

		cout << "请输入性别:" << endl;
		cout << "1---男" << endl;
		cout << "2---女" << endl;
		int sex = 0;
		cin >> sex;
		while (true) {
			if (sex == 1 || sex == 2) {
			abs->personArray[ret].m_Sex = sex;
		 	break;
			}
		cout << "输入有误,请重新输入" << endl;
	    }
		
		cout << "请输入年龄:" << endl;
		int age=0;
		cin >> age;
		abs->personArray[ret].m_Age = age;


		cout << "请输入联系电话:" << endl;
		string phone;
		cin >> phone;
		abs->personArray[ret].m_Phone = phone;


		cout << "请输入家庭住址:" << endl;
		string address;
		cin >> address;
		abs->personArray[ret].m_Addr = address;


		cout << "修改成功!" << endl;

	}
	else {
		cout << "查无此人" << endl;
	}
	system("pause");
	system("cls");

}
//清空联系人
void cleanPerson(Addressbooks*abs) {
	cout << "您是否确定要删除所有联系人?" << endl;
	cout << "输入 Y 为确定   " ;
	cout << "输入其他键则返回主菜单" << endl;
	char a ;
	cin >> a;
	if (a == 'Y') {
		int ret = abs->m_Size;
		if (ret == 0) {
			cout << "本来就是空的!" << endl;
			system("pause");
			system("cls");
			return;

		}
		else {
			abs->m_Size = 0;//逻辑清空
			cout << "清除成功!" << endl;
			system("pause");
			system("cls");
		}
		
	}
	else {
		system("pause");
		system("cls");
		return;
	}

}
//菜单显示
void showMenu() {
	cout << "*****************************" << endl;
	cout << "*****	1.添加联系人	*****" << endl;
	cout << "*****	2.显示联系人	*****" << endl;
	cout << "*****	3.删除联系人	*****" << endl;
	cout << "*****	4.查找联系人	*****" << endl;
	cout << "*****	5.修改联系人	*****" << endl;
	cout << "*****	6.清空联系人	*****" << endl;
	cout << "*****	0.退出该系统	*****" << endl;
	cout << "*****************************" << endl;
}
int main()
{

	//创建通讯录结构体变量
	Addressbooks abs;
	//初始化通讯录中当前人员个数
	abs.m_Size = 0;


	int select = 0;//创建用户选择输入的变量
	while (true) {//循环使用
		//菜单调用
		showMenu();
		//用户选择想要功能
		cin >> select;

		switch (select) {
		case 1://添加联系人
			addPerson(&abs);
			break;
		case 2:// 显示联系人
			showPerson(&abs);
			break;
		case 3: // 删除联系人
			deletePerson(&abs);
			break;
		case 4://查找联系人
			findPerson(&abs);
			break;
		case 5://修改联系人
			modifyPerson(&abs);
			break;
		case 6:// 清空联系人
			cleanPerson(&abs);
			break;
		case 0:// 退出通讯录
			cout << "欢迎下次使用,再见!" << endl;
			system("pause");
			return 0;
			break;
		default:
			break;
		}
	}


	system("pause");
	return 0;


}

项目演示

11.jpg
12.jpg
13.jpg
14.jpg
15.jpg
16.jpg
17.jpg
18.jpg
20.jpg


文章发布自:黑凤梨の博客,转载请注明出处,谢谢!

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦