C++学习笔记

#include <iostream>
using namespace std;

int main()
{
	//代码内容
	//cout << "hello world" << endl;
	
	system("pause");
	return 0;
}

注释

作用:在代码中加一些说明和解释,方便自己或其他程序员阅读代码
方式一://单行注释
方式二:/*多行注释 */

变量

作用:给一段指定的内存空间起名,方便操作这段内存
存在意义:方便管理内存空间
语法:数据类型 变量名 = 初始值

#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	cout << "a = " << a << endl;
	
	system("pause");
	return 0;
}

常量

作用:用于记录程序中不可更改的数据
C++定义常量的两种方法:
1、#define宏常量
语法:#define 变量名 常量值
通常在文件上方定义,表示一个常量
2、const修饰的变量
语法:const 数据类型 变量名 = 常量值
通常在变量定义前加关键字const,修饰该变量为常量,不可更改。

#include <iostream>
using namespace std;
//宏常量
#define day 7

int main()
{
	//day = 8;
	//错误,常量不可更改
	cout << "一周有 " << day << "天" << endl;
	
	const  month = 12;
	//month = 24;
	//错误,常量不可更改
	cout << "一年有 " << month << "个月份" << endl;
	
	system("pause");
	return 0;
}

关键字

作用:关键字是C++中预先保留的单词(标识符)
注意:在定义变量和常量的时候,不能使用关键字,否则会报错

标识符命名规则

作用:C++规定给标识符(常量、变量)命名时,有一套自己的规则
规则:
1、标识符不能是关键字;
2、标识符只能由字母、数字、下划线组成;
3、第一个字符必须为字母或下划线;
4、标识符中区分大小写。

数据类型

C++规定在创建一个变量或常量时,必须要指定出相应的数据类型,否则无法给变量分配内存
存在意义:给变量分配合适的空间

整型

作用:表示整数类型的数据
分类(所占空间不同):
short(短整型) 占用2字节空间
int (整型) 占用4字节空间
long(长整型) Windows占用4字节,Linux占用4(32位)或8(64位)字节
long long(长长整形) 占用8字节空间

#incude <iostream>
using namespace std;
#define day 7

int main()
{
	short a = 5;
	int b = 10;
	long c = 15;
	long long d = 20;
	//区别于c语言的long long int a = 10;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;
	
	system("pause");
	return 0;
}
sizeof关键字

作用:利用sizeof关键字可以统计数据类型所占内存的大小
语法:sizeof(数据类型/变量)

#incude <iostream>
using namespace std;

int main()
{
	cout << "int类型所占内存空间为:" << sizeof(int) << endl;

	system("pause");
	return 0;
}	

整型大小比较:short <int <=long <=long long

实型(浮点型)

作用:用于表示小数
分类:(表示的有效数字范围不同)
单精度float 占用4字节 7位有效数字
双精度double 占用8字节 15~16位有效数字

#include <iostream>
using namespace std;

int main()
{
	float a = 3.14;
	float b = 3.14f;
	//在数字后加f可以减少程序转换的过程
	double c = 3e2;
	//科学计数法,表示3*10的平方
	double d = 3e-2;
	//科学计数法,表示3*0.1的平方
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;

	system("pause");
	return 0;
}
字符型

作用:用于显示单个字符
语法:char ch = ‘a’;
注意:
1、在现实字符型变量时,用单引号将字符括起来,而不是双引号;
2、单引号内只能有一个字符,不可以是字符串。
C和C++中字符串变量都只占用1个字节
字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码[a 97, A 65]放入存储单元。

#include <iostream>
using namespace std;

int main()
{
	char ch = 'a';
	cout << ch << endl;

	ch = 97;
	//可以直接用ASCII编码给字符型变量赋值
	cout << ch << endl;
	
	system("pause");
	return 0;
}

转义字符

作用:用于表示一些不能显示出来的ASCII字符。
转义字符 | 含义
\a | 报警
\b | 退格,将当前位置移到前一列
\f | 换页,将当前位置移到下页开头
\n | 换行,将当前位置移到下一行开头
\r | 回车,将当前位置移到本行开头
\t | 水平制表(跳到下一个TAB位置)一个\t占8个位置
\v | 垂直制表
\\ | 表示反斜线
\’ | 表示单引号字符
\? | 表示一个?

#include <iostream>
using namespace std;

int main()
{
	cout << "aaa\thelloworld" <<endl;
	//水平制表符作用:整齐输出内容
	cout << "aaaa\thelloworld" <<endl;
	system("pause");
	return 0;
}

结果:
aaa helloworld
aaaa helloworld

字符串型

作用:用于表示一串字符
两种风格:
1、C风格字符串
语法:char 变量名[] = “字符串值”
注意:字符串要用双引号括起来
2、C++风格字符串
语法:string 变量名 = “字符串值”
注意:要包含头文件#include

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

int main()
{
	char str1[] = "hello";
	cout << str1 << endl;
	string str2[] = "world";
	cout << str2 << endl;
	
	system("pause");
	return 0;
}
布尔类型 bool

作用:布尔数据类型代表真或假的值
bool类型只有两个值:
1、true -真(本质是1)
2、false -假(本质是0)
bool类型占据1个字节大小

#include <iostream>
using namespace std;

int main()
{
	bool flag = true;
	cout << flag <<endl;//1
	//只要是非0的值则flag的值就为真

	flag = false;
	cout << flag <<endl;//0
	
	system("pause");
	return 0;
}
数据的输入

作用:用于从键盘获取数据
关键字:cin
语法:cin >> 变量

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

int main()
{
	int a = 0;
	cout << "请给整型变量a赋值:" <<endl;
	cin >> a;
	cout << "a = " << a << endl;
	float b;
	cout << "请给浮点型变量f赋值:" <<endl;
	cin >> f;
	cout << "f = " << f << endl;
	char ch;
	cout << "请给字符型变量ch赋值:" <<endl;
	cin >> ch;
	cout << "ch = " << ch << endl;
	string str = "hello";
	cout << "请给字符串str赋值:" <<endl;
	cin >> str;
	cout << "str = " << str << endl;
	bool flag = false;
	cout << "请给布尔类型flag赋值:" <<endl;
	cin >> flag;
	cout << "flag = " << flag << endl;
	
	system("pause");
	return 0;
}

运算符

作用:用于执行代码的运算

算数运算符(同C语言)

作用:用于处理四则运算
包括:
+(正号)、-(负号)、+、-、*、
/、%、(除数不能为0,且两个小数不能进行取模运算)
++(前置递增)、(先加1,后运算)
++(后置递增)、(先运算,后加1)
–(前置递减)、–(后置递减)

赋值运算符(同C语言)

作用:用于将表达式的值赋给变量
包括:
=、+=、-=、*=、/=、%=

比较运算符(同C语言)

作用:用于表达式的比较
包括:
==、!=、<=、>=、<、>

逻辑运算符

作用:用于根据表达式的值返回真值或假值
包括:
!(非)、[a为真,则!a为假]
&&(与)、[一假则假]
||(或)[一真则真]

程序流程结构

C/C++支持的最基本的三种程序运行结构:
顺序结构:程序按顺序执行,不发生跳转
选择结构:依据条件是否满足,有选择的执行相应功能
顺序结构:依据条件是否满足,循环多次执行某段代码

选择结构

if语句
作用:执行满足条件的语句
三种形式:
1、单行合适if语句
语法 :if (条件) {条件满足执行的语句}
在这里插入图片描述

#include <iostream>
using namespace std;

int main ()
{
	int score = 0;
	cout << "请输入分数:" << endl;
	cin >> score;
	cout << "您输入的分数为:" << score << endl;
	if (score > 550)//注意:这里不能加分号
	{
		cout << "恭喜您考上了一本大学" << endl;
	}
	
	system("pause");
	return 0;
}

2、多行格式if语句
语法:if(条件) {条件满足执行的语句} else {条件不满足执行的语句};
在这里插入图片描述

#include <iostream>
using namespace std;

int main ()
{
	int score = 0;
	cout << "请输入分数:" << endl;
	cin >> score;
	cout << "您输入的分数为:" << score << endl;
	if (score > 550)//注意:这里不能加分号
	{
		cout << "恭喜您考上了一本大学" << endl;
	}
	else 
	{
		cout << "未考上一本大学" << endl;
	}
	
	system("pause");
	return 0;
}

3、多条件的if语句
语法:if(条件1){条件一满足执行的语句} else if (条件2){条件2满足执行的语句}…else {都不满足执行的语句}
在这里插入图片描述

#include <iostream>
using namespace std;

int main ()
{
	int score = 0;
	cout << "请输入分数:" << endl;
	cin >> score;
	cout << "您输入的分数为:" << score << endl;
	if (score > 550)//注意:这里不能加分号
	{
		cout << "恭喜您考上了一本大学" << endl;
	}
	else if (score > 450)
	{
		cout << "恭喜您考上了二本大学" << endl;
	}
	else if (score > 350)
	{
		cout << "恭喜您考上了三本大学" << endl;
	}
	else 
	{
		cout << "未考上本科大学" << endl;
	}
	
	system("pause");
	return 0;
}

嵌套if语句

#include <iostream>
using namespace std;

int main ()
{
	int score = 0;
	cout << "请输入分数:" << endl;
	cin >> score;
	cout << "您输入的分数为:" << score << endl;
	if (score > 550)//注意:这里不能加分号
	{
		if (score > 700)
		{
			cout << "恭喜您考上了北京大学" << endl;
		}
		else if (score > 650)
		{
			cout << "恭喜您考上了清华大学" << endl;
		}
		else 
		{
			cout << "恭喜您考上了一本大学" << endl;
		}
	}
	else if (score > 450)
	{
		cout << "恭喜您考上了二本大学" << endl;
	}
	else if (score > 350)
	{
		cout << "恭喜您考上了三本大学" << endl;
	}
	else 
	{
		cout << "未考上本科大学" << endl;
	}
	
	system("pause");
	return 0;
}

三目运算符
作用:通过三目运算符实现简单的判断
语法:表达式1 ?表达式2 : 表达式3
解释
如果表达式1的值为真,执行表达式2,并返回表达式2的结果;
如果表达式1的值为假,执行表达式3,并返回表达式3的结果。

#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	
	c = (a > b ? a : c);
	//将a和b作比较,并将较大的值赋给变量c

	cout << "c = " << c << endl;

	//在C++中三目运算符返回的是变量,可以继续赋值
	(a > b ? a : b) = 100;
	cout << "a = " << a << endl;//10
	cout << "b = " << b << endl;//100
	
	system("pause");
	return 0;
}

switch语句
作用:执行多条件分支语句
语法:

switch (表达式)

{
	case 结果1 :执行语句;break;
	case 结果2 :执行语句;break;
	...

	default:执行语句;break;
}
#include <iostream>
using namespace std;

int main()
{
	int score = 0;
	cout << "请给电影打分:" << endl;
	cin >> score;
	cout << "您打的分数是:" << endl;
	switch (score)
	{
	case  10:
		cout << "您认为是经典电影" << endl;
		break;//退出当前分支
	case  9:
		cout << "您认为是经典电影" << endl;
		break;
	case  8:
		cout << "您认为电影非常好" << endl;
		break;
	case  7:
		cout << "您认为电影非常好" << endl;
		break;
	case  6:
		cout << "您认为电影一般" << endl;
		break;
	case  5:
		cout << "您认为电影一般" << endl;
		break;
	default :
		cout << "您认为电影是烂片" << endl;
		break;
	
	system("pause");
	return 0;
}

if和switch的区别:
switch判断类型只能是整型或者字符型,不可以是一个区间
case里如果没有break,那么程序会一直向下执行
switch的结构清晰,执行效率高

循环结构

while语句
作用:满足循环条件,执行循环语句
语法:while (循环条件) {循环语句}
解释:只要循环条件的结果为真,就执行循环语句
在这里插入图片描述

#include <iostream>
using namespace std;

int main()
{
	int num = 0;
	//要避免死循环的条件
	while (num  < 10)
	{
		cout << num << endl;
		num++;
	}//从数字0打印到数字9
	
	system("pause");
	return 0;
}

生成随机数

int num = rand()%100 + 1//生成1~100的随机数   伪随机数
int num2 = srand((unsigned int)time(NULL));//随机数种子

可利用break来退出循环
do while循环语句
作用:满足循环条件,执行循环语句
语法:do {循环语句} while (循环条件)
注意:与while的区别在于do…while会先执行一次循环语句,再判断循环条件
在这里插入图片描述

#include <iostream>
using namespace std;

int main()
{
	int num = 0;
	do{
		cout << num << endl;
		num++;
	}while (num  < 10);//从数字0打印到数字9
	//先执行一次循环语句再循环
	
	system("pause");
	return 0;
}

for循环语句
作用:满足循环条件,执行循环语句
语法:for(起始表达式;条件表达式;末尾循环体){循环语句}

#include <iostream>
using namespace std;

int main()
{
	//从数字0打印到数字9
	for (int i = 0;i < 10;i++)
	{
		cout << i << endl;
	}
	
	system("pause");
	return 0;
}

注意:for循环的表达式,要用分号来进行分割
嵌套循环
作用:在循环体中再嵌套一层循环,解决一些实际问题

#include <iostream>
using namespace std;

int main()
{
	//从数字0打印到数字9
	for (int i = 0;i < 10;i++)//外层循环
	{
		for (int j = 0;j < 10;j++)//内层循环
		{
			cout << "* " ;
		}
		cout << endl;
	}
	
	system("pause");
	return 0;
}
跳转语句

break语句
作用:用于跳出选择结构或者循环结构
break使用的时机:
1、出现在switch条件语句中,作用是终止case并跳出switch;
2、出现在循环语句中,作用是跳出当前的循环语句;
3、出现在嵌套循环中,跳出最近的内层循环语句。

#include <iostream>
using namespace std;

int main()
{
	//switch语句中
	cout << "请选择副本难度" << endl;
	cout << "1、普通" << endl;
	cout << "2、中等" << endl;
	cout << "3、困难" << endl;
		
	int select = 0;
	cin >> select;

	switch(select)
	{
	case 1:
		cout << "您选择的是普通难度" << endl;
		break;//退出switch语句
	case 2:
		cout << "您选择的是中等难度" << endl;
		break;
	case 3:
		cout << "您选择的是困难难度" << endl;
		break;
	default:
		break;
	}
	
	//循环语句中
	for (int i = 0; i < 10;i++)
	{
		if(i == 5)
		{
			break;//退出循环
		}
		cout << i << endl;
	}
		
	//嵌套循环语句中
	for (int i = 0;i < 10;i++)
	{
		for (int j = 0;j < 10;j++)
		{
			if (j == 5)
			{
				break;
			}//退出内层循环
			cout << "* " ;
		}
		cout << endl;
	}
	
	system("pause");
	return 0;
}

continue语句
作用:在循环语句中,跳过本次循环中尚未执行的语句,继续执行下一次循环

#include <iostream>
using namespace std;

int main()
{
	for (int i = 0; i <= 100; i++)
	{
		//如果是奇数输出,偶数不输出
		if (i % 2 == 0)
		{
			continue;//break会退出循环,而continue不会
		}
		cout << i << endl;
	}
	
	system("pause");
	return 0;
}

goto语句
不推荐使用
作用:可以无条件跳转语句
语法:goto 标记;
解释:如果标记的名称存在,执行到goto语句时,会跳转到标记的位置

#include <iostream>
using namespace std;

int main()
{
	cout << "1" << endl;
	cout << "2" << endl;
	goto FLAG;
	cout << "3" << endl;
	cout << "4" << endl;
	FLAG://若不存在标记程序会报错
	cout << "5" << endl;
	
	system("pause");
	return 0;
}

数组

所谓数组,就是一个集合,里面存放了相同元素的数据类型
特点
1、数组中的每个数据元素都是相同的数据类型;
2、数组是由连续的内存位置组成的。

一维数组的定义方式

一维数组的定义方式:
1、数据类型 数组名【 数组长度】
2、数据类型 数组名【 数组长度】 = { 值1,值2 …};
3、数据类型 数组名 【】= { 值1,值2 …};
注意
1、数组名的命名规范与变量名命名规范一致,不要和变量名重名
2、数组中下标是从0开始的

#include <iostream>
using namespace std;

int main()
{
	int arr1[5];
	arr1[0] = 10;
	arr1[1] = 20;
	arr1[2] = 30;
	arr1[3] = 40;
	arr1[4] = 50;
	for (int i = 0; i < 5; i++)
	{
		cout << arr1[i] << endl;
	}//利用循环输出数组中的元素
	int arr2[5] = {11,12,13,14,15};
	//若在初始化时没有全部填写完,会用0来代替
	for (int i = 0; i < 5; i++)
	{
		cout << arr2[i] << endl;
	}
	int arr3[] = {21,22,23,24,25,26,27,28};
	for (int i = 0; i < 8; i++)
	{
		cout << arr2[i] << endl;
	}
	
	system("pause");
	return 0;
}
一维数组数组名

一维数组名称的用途:
1、可以统计整个数组在内存中的长度;
2、可以获取数组在内存中的首地址。

#include <iostream>
using namespace std;

int main()
{
	int arr[5] = {1,2,3,4,5};
	int a = sizeof(arr);//统计整个数组占用内存大小
	int b = sizeof(arr[0]);//统计数组中一个元素占用内存大小
	cout << "数组arr占用内存为:" << a << endl;
	cout << "数组arr中第一个元素占用内存为:" << b << endl;
	cout << "数组arr中元素个数为:" << a/b << endl;
	
	cout << "数组的首地址为:" << arr << endl;//输出十六进制下的数组首地址
	//vc中
	//cout << "数组的首地址为:" << (int)arr << endl;//输出十进制下的数组首地址
	//cout << "数组的第一个元素的地址为:" << (int)&arr[0] << endl;
	//cout << "数组的第二个元素的地址为:" << (int)&arr[1] << endl;//与上一个差b个字节
	
	//arr = 100;
	//错误,数组名是常量,不可以进行赋值操作
	
	system("pause");
	return 0;
}
冒泡排序

作用:最常用的排序算法,对数组内元素进行排序
步骤:
1、比较相邻的元素。如果第一个比第二个大,就交换它们两个;
2、对每一对相邻元素做同样的工作,执行完毕后,找到第一个最大值
3、重复以上的步骤,每次比较次数-1,直到不需要比较。

#include <iostream>
using namespace std;

int main()
{
	int arr[9] = {4,2,8,0,5,7,1,3,9};

	cout << "排序前:" << endl;
	for (int i = 0;i < 9;i++)
	{
		cout << arr[i] << "";
	}
	cout << endl;

	//冒泡排序
	forint i = 0; i < 8; i++)
	{
		//内层循环对比
		for (int j = 0; j < 8 - i; j++)
		{
			if (arr[j] > arr[j+1])
			{
				int temp = arr[j+1];
				arr[j+1] = arr[j];
				arr[j] = temp;
			}
		}
	}
	cout << "排序后:" << endl;
	for (int i = 0;i < 9;i++)
	{
		cout << arr[i] << "";
	}
	cout << endl;

	system("pause");
	return 0;
}

二维数组(在一维数组上多加一个维度)

二维数组定义方式:

​ 1、数据类型 数组名 [ 行数 ] [ 列数 ];
​ 2、数据类型 数组名 [ 行数 ] [ 列数 ] = { {数据1,数据2},{数据3,数据4} };
​ 3、数据类型 数组名 [ 行数 ] [ 列数 ] = { 数据1,数据2,数据3,数据4 };
​ 4、数据类型 数组名 [ ] [ 列数 ] = { 数据1,数据2,数据3,数据4 };
建议:第二种更直观,提高代码的可读性

#include <iostream>
using namespace std;

int main() {
	int arr[2][3];
	arr[0][0] = 1;
	arr[0][1] = 2;
	arr[0][2] = 3;
	arr[1][0] = 4;
	arr[1][1] = 5;
	arr[1][2] = 6;
	//外层循环打印行数,内层循环打印列数
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr[i][j] << " ";
		}
		cout << endl;
	}
	int arr2[2][3] = { {1,2,3},{4,5,6} };
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr2[i][j] << " ";
		}
		cout << endl;
	}
	int arr3[2][3] = { 1,2,3,4,5,6 };
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr3[i][j] << " ";
		}
		cout << endl;
	}
	int arr4[][3] = {1, 2, 3, 4, 5, 6};
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr4[i][j] << " ";
		}
		cout << endl;
	}

system("pause");
return 0;
}

二维数组数组名

作用:
1、查看二维数组所占内存空间
2、获取二维数组首地址

#include <iostream>
using namespace std;

int main() {
	int arr[2][3] = 
	{ 
		{1,2,3},
		{4,5,6}
	};
	cout << "二维数组占用内存空间为:" << sizeof(arr) << endl;
	cout << "二位数组第一行占用内存为:" << sizeof(arr[0]) << endl;
	cout << "二位数组第一个元素占用内存为:" << sizeof(arr[0][0]) << endl;

	cout << "二维数组的行数为:" << sizeof(arr) / sizeof(arr[0]) << endl;
	cout << "二维数组的列数为:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;

	cout << "二维数组的首地址为:" << (int)arr << endl;
	cout << "二维数组第一行的首地址为:" << (int)arr[0] << endl;
	cout << "二维数组第一个元素的地址为:" << (int)&arr[0][0] << endl;
	cout << "二维数组第二行的首地址为:" << (int)arr[1] << endl;
	//与第一行差sizeof(arr[0])个字节

system("pause");
return 0;
}

函数

作用:将一段经常使用的代码封装起来,减少重复代码
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能

函数的定义

定义步骤
1、返回值类型
2、函数名
3、参数列表(形参)
4、函数体语句
5、return表达式
语法

返回值类型  函数名  (参数列表)
{
	函数体语句

	return 表达式
}

定义示例

int add(int num1, int num2)
{
	int sum;
	sum = num1 + num2;

	return sum;
}

函数的调用

功能:使用定义好的函数
语法:函数名(实际参数)

#include <iostream>
using namespace std;

int add(int num1, int num2)
{
	int sum;
	sum = num1 + num2;

	return sum;
}

int main() {
	int a = 10;
	int b = 20;
	int c;
	c = add(a, b);
	cout << "和为:" << c << endl;

	system("pause");
	return 0;
}

值传递

定义:在函数调用时,实参将数值传入形参
值传递时,如果形参发生变化,并不会影响实参

#include <iostream>
using namespace std;

void swap(int num1, int num2)//不需要返回值
{
	cout << "交换前:" << endl;
	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;
	int temp = num1;
	num1 = num2;
	num2 = temp;

	cout << "交换后:" << endl;
	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;

	return;//不需要返回值时,可以不写return语句
}

int main() {
	int a = 10;
	int b = 20;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	
	//值传递时,函数的形参发生改变并不会影响实参
	swap(a, b);
	cout << "a = " << a << endl;//并未改变
	cout << "b = " << b << endl;

	system("pause");
	return 0;
}

函数常见样式

	1、无参无返
	2、有参无返
	3、无参有返
	4、有参有返
#include <iostream>
using namespace std;

//无参无返
void test01( )
{
	cout << "this is test01" << endl;
}
//有参无返
void test02(int a)
{
	cout << "this is test02 a = " << a << endl;
}
//无参有返
int test03()
{
	cout << "this is test03" << endl;

	return 1000;
}

//有参有返
int test04(int a)
{
	cout << "this is test04 a = " << a << endl;

	return a;
}

int main() {
	test01();
	test02(100);
	int a = test03();
	cout << "a =  " << a << endl;
	int b = test04(10000);
	cout << "b =  " << b << endl;

	system("pause");
	return 0;
}

函数的声明

作用:告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义
函数的声明可以多次,但是函数的定义只能有一次

#include <iostream>
using namespace std;
int max(int a, int b);//函数的声明
//提前告诉编译器函数的存在

int main() {
	int a = 10;
	int b = 20;

	cout << max(a, b) << endl;

	system("pause");
	return 0;
}

//有函数声明时,函数定义可以放在main函数后面,否则会报错
int max(int a, int b)
{
	return a > b ? a : b;
}

函数的分文件编写

作用:让代码结构更加清晰
原文件:

#include <iostream>
using namespace std;

void swap(int a, int b)//不需要返回值
{
	int temp = a;
	a = b;
	b = temp;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	return;//不需要返回值时,可以不写return语句
}

int main() {
	int a = 10;
	int b = 20;

	swap(a, b);

	system("pause");
	return 0;
}

编写步骤:
1、创建后缀名为.h的头文件
在这里插入图片描述
在这里插入图片描述
2、创建后缀名为.cpp的源文件
在这里插入图片描述在这里插入图片描述
3、在头文件中写函数的声明
在这里插入图片描述
4、在源文件中写函数的定义
在这里插入图片描述
调用:
在这里插入图片描述

指针

指针的基本概念

指针的作用:可以通过指针间接访问内存
内存编号是从0开始记录的,一般用十六进制数字表示
可以利用指针变量保存地址

指针变量的定义和使用

指针变量定义语法:数据类型 * 变量名

#include <iostream>
using namespace std;

int main() {
	int a = 10;
	//定义指针
	int * p;
	//让指针记录变量a的地址
	p = &a;

	cout << "a的地址为:" << &a << endl;
	cout << "指针p的值为:" << p << endl;//结果同上

	//使用指针
	//通过解引用找到指针指向的内存
	*p = 1000;
	cout << "a = " << a << endl;
	cout << "*p = " << *p << endl;

	system("pause");
	return 0;
}

指针所占内存空间

在32位操作系统下,指针占4个字节空间大小,不管是什么数据类型
在64位操作系统下,指针占8个字节空间大小

#include <iostream>
using namespace std;

int main() {
	int a = 10;
	int * p;
	p = &a;

	cout << "sizeof(int *) = " << sizeof(p) << endl;
	cout << "sizeof(float *) = " << sizeof(float *) << endl;
	cout << "sizeof(double *) = " << sizeof(double *) << endl;
	cout << "sizeof(char *) = " << sizeof(char *) << endl;

	system("pause");
	return 0;
}

空指针

定义:指针变量指向内存中编号为0的空间
作用:初始化指针变量
注意:空指针指向的内存是不可以访问的
原因:0~255之间的内存编号是系统占用的,因此不可以访问

#include <iostream>
using namespace std;

int main() {
	//空指针用于给指针变量进行初始化
	int * p = NULL;

	//*p = 100;
	//错误,空指针是不可以访问的

	system("pause");
	return 0;
}

野指针

定义:指针变量指向非法的内存空间

#include <iostream>
using namespace std;

int main() {
	//野指针
	int * p = (int *)0x1100;
	//异常,读取访问程序出错

	//访问野指针报错
	cout << *p << endl;

	system("pause");
	return 0;
}

const修饰指针

const修饰指针的三种情况:
1、const修饰指针 ——— 常量指针[const int * p = &a]
特点:指针的指向可以修改,但指针指向的值不可以修改
2、const修饰常量 ———指针常量[int * cont p = &a]
特点:指针的指向不可以修改,但指针指向的值可以修改
3、const既修饰指针,又修饰常量[const int *const p = &a]
特点:指针的指向和指针指向的值都不可以修改

#include <iostream>
using namespace std;

int main() {
	int a = 10;
	int b = 10;

	const int * p = &a;
	//*p = 20;错误
	p = &b;//正确

	int * const p2 = &a;
	*p2 = 20;//正确
	//p2 = &b;错误

	const int * const p3 = &a;
	//*p3 = 100;错误
	//p3 = &b;错误

	system("pause");
	return 0;
}

指针和数组

作用:利用指针访问数组中元素

#include <iostream>
using namespace std;

int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	cout << "第一个元素为:" << arr[0] << endl;

	int * p = arr;//arr就是数组首地址

	cout << "利用指针访问第一个元素:" << *p << endl;

	p++;//让指针向后偏移4个字节

	cout << "利用指针访问第二个元素:" << *p << endl;

	int *p2 = arr;

	cout << "利用指针遍历数组" << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << *p2 << endl;
		p2++;
	}

	system("pause");
	return 0;
}

指针和函数

作用:利用指针作为函数参数,可以修改实参的值

#include <iostream>
using namespace std;

void swap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;

	cout << "swap01 a = " << a << endl;
	cout << "swap01 b = " << b << endl;
}

void swap02(int *p1, int *p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;

	cout << "swap02 a = " << *p1 << endl;
	cout << "swap02 b = " << *p2 << endl;
}

int main() {
	//值传递
	int a = 10;
	int b = 20;
	swap01(a, b);
	//值传递不会修改实参的值
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	//地址传递
	swap02(&a, &b);
	//地址传递可以修改实参,更改了指针指向的值
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	system("pause");
	return 0;
}

指针、数组、函数

案例:封装一个函数,利用冒泡排序实现对整形数组的升序排序

#include <iostream>
using namespace std;

//冒泡排序函数   参数1:数组的首地址,参数2:数组长度
void bubbleSort(int *arr,int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

//打印数组
void printArry(int *arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
}

int main() {
	//创建数组
	int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };

	int len = sizeof(arr) / sizeof(arr[0]);
	//创建函数,实现冒泡排序
	bubbleSort(arr, len);

	//打印排序后的数组
	printArry(arr, len);

	system("pause");
	return 0;
}

结构体

结构体的基本概念

结构体数与用户自定义的数据类型,允许用户存储不同的数据类型

结构体的定义和使用

语法:struct 结构体名 { 结构体成员列表 };
通过结构体创建变量的方式:
1、struct 结构体名 变量名
2、struct 结构体名 变量名 = { 成员1值,成员2值…}
3、定义结构体时顺便创建变量不建议使用

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

//创建学生数据类型  :学生包括:姓名,年龄,分数
//结构体定义时,struct关键字不可以省略
struct Student
{
	//姓名
	string name;
	//年龄
	int age;
	//分数
	int score;
}s3;
//法三

int main() {
	//通过学生类型创建具体学生
	//法一
	struct Student s1;
	//结构体变量创建时,struct关键字可以省略
	//Student s1;
	//给s1属性赋值
	s1.name = "张三";
	s1.age = 18;
	s1.score = 100;

	cout << "姓名:" << s1.name << "年龄:" << s1.age 
		<< "分数: " << s1.score << endl;

	//法二
	struct Student s2 = { "李四",19,80 };

	cout << "姓名:" << s2.name << "年龄:" 
		<< s2.age << "分数: " << s2.score << endl;

	//法三,在定义结构体时创建结构体变量
	s3.name = "王五";
	s3.age = 20;
	s3.score = 60;

	cout << "姓名:" << s3.name << "年龄:" << s3.age 
		<< "分数: " << s3.score << endl;

	system("pause");
	return 0;
}

结构体数组

作用:将自定义的结构体放入到数组中方便维护
语法:struct 结构体名 数组名[元素个数] = { {}, {} ,…{} }

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

//定义结构体
struct Student
{
	//姓名
	string name;
	//年龄
	int age;
	//分数
	int score;
};

int main() {
	//创建结构体数组并赋值
	struct Student stuArray[3]=
	{
		{"张三",18,100},
		{"李四",19,99},
		{"王五",20,66}
	};
	//修改数值
	stuArray[2].age = 19;

	//遍历结构体数组
	for (int i = 0; i < 3; i++)
	{
		cout << " 姓名: " << stuArray[i].name 
			<< " 年龄:" << stuArray[i].age 
			<< " 分数:" << stuArray[i].score << endl;
	}

	system("pause");
	return 0;
}

结构体指针

作用:通过指针访问结构体中的成员
利用操作符->可以通过结构体指针访问结构体属性

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

//定义学生结构体
struct Student
{
	string name;//姓名
	int age;//年龄
	int score;//分数
};

int main() {
	//创建学生结构体变量
	struct Student s = { "张三",18,100 };//struct可以省略
	
	//通过指针指向结构体变量
	//int *p = &s;错误
	struct Student * p = &s;//struct可以省略

	//通过指针访问结构体变量中的数据
	cout << " 姓名:" << p->name
		<< " 年龄:" << p->age
		<< " 分数:" << p->score << endl;

	system("pause");
	return 0;
}

结构体嵌套结构体

作用:结构体中的成员可以是另一个结构体
在结构体中定义另一个结构体作为成员,用以解决实际问题

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

//定义学生结构体
struct Student
{
	string name; //姓名
	int age;     //年龄
	int score;   //分数
};

//教师结构体定义
struct Teacher
{
	int id;              //教师编号
	string name;         //教师姓名
	int age;             //年龄
	struct Student stu;  //辅导的学生
};

int main() {
	//创建老师
	Teacher t;
	t.id = 10000;
	t.name = "老王";
	t.age = 50;
	t.stu.name = "小王";
	t.stu.age = 20;
	t.stu.score = 60;

	cout << " 老师姓名:" << t.name
		<< " 老师标号:" << t.id
		<< " 老师年龄:" << t.age
		<< " 老师辅导的学生姓名:" << t.stu.name
		<< " 老师辅导的学生年龄:" << t.stu.age
		<< " 老师辅导的学生分数:" << t.stu.score << endl;

	system("pause");
	return 0;
}

结构体做函数参数

作用:将结构体作为参数向函数中传递
传递方式:
1、值传递
2、地址传递

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

//定义学生结构体
struct Student
{
	string name; //姓名
	int age;     //年龄
	int score;   //分数
};

//值传递
void printStudent1(struct Student s)
{
	s.age = 100;
	cout << "子函数1中  姓名:" << s.name 
		<< " 年龄:" << s.age << " 分数:" << s.score << endl;
}

//地址传递
void printStudent2(struct Student * p)
{
	p->age = 100;
	cout << "子函数2中  姓名:" << p->name 
		<< " 年龄:" << p->age << " 分数:" << p->score << endl;
}

int main() {
	//创建结构体变量
	Student s;
	s.name = "张三";
	s.age = 20;
	s.score = 85;

	cout << "main函数中  姓名:" << s.name 
		<< " 年龄:" << s.age << " 分数:" << s.score << endl;

	printStudent1(s);
	cout << "main函数中  姓名:" << s.name 
		<< " 年龄:" << s.age << " 分数:" << s.score << endl;//年龄未被改变

	printStudent2(&s);
	cout << "main函数中  姓名:" << s.name 
		<< " 年龄:" << s.age << " 分数:" << s.score << endl;//年龄被改变

	system("pause");
	return 0;
}

结构体中const使用场景

作用:用const来防止误操作

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

struct Student //定义学生结构体
{
	string name; //姓名
	int age;     //年龄
	int score;   //分数
};

//将函数中的形参改为指针,可以减少内存空间
void printStudents(const Student * s)
{
	//s->age = 150;
	//错误,加入const后s不可修改,可防止误操作
	cout << " 姓名:" << s->name << " 年龄:" << s->age 
		<< " 分数:" << s->score << endl;
}

int main() {
	//创建结构体变量
	struct Student s = { "张三",15,70 };

	cout << "main函数中张三的年龄为:" << s.age << endl;

	//通过函数来打印结构体变量信息
	printStudents(&s);

	cout << "main函数中张三的年龄为:" << s.age << endl;

	system("pause");
	return 0;
}

结构体案例1

在这里插入图片描述

#include <iostream>
using namespace std;
#include <string>//c++字符串需要的头文件
#include <ctime>//随机数种子需要的头文件

struct Student //定义学生结构体
{
	string sName; //姓名
	int score;   //分数
};

struct Teacher //定义老师结构体
{
	string tName; //姓名
	struct Student sArray[5];
};

//给老师和学生赋值的函数
void allocateSpace(struct Teacher tArray[],int len)
{
	string nameSeed = "ABCDE";
	//给老师赋值
	for (int i = 0; i < len; i++)
	{
		tArray[i].tName = "Teacher_";
		tArray[i].tName += nameSeed[i];

		//给老师带的学生赋值
		for (int j = 0; j < 5; j++)
		{
			tArray[i].sArray[j].sName = "Student_";
			tArray[i].sArray[j].sName += nameSeed[j];

			int random = rand() % 61 + 40;//40~100分区间内的随机数
			tArray[i].sArray[j].score = random;
		}
	}
}

void printInfo(struct Teacher tArray[],int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << "老师姓名:" << tArray[i].tName << endl;

		for (int j = 0; j < 5; j++)
		{
			cout << "\t学生姓名:" << tArray[i].sArray[j].sName 
				<< " 考试分数:" << tArray[i].sArray[j].score << endl;
		}
	}
}

int main() {
	//随机数种子
	srand((unsigned int)time(NULL));

	//创建老师数组
	Teacher tArray[3];

	//通过函数给老师和学生信息赋值
	int len = sizeof(tArray) / sizeof(tArray[0]);
	allocateSpace(tArray, 3);

	//打印所有老师及学生信息
	printInfo(tArray, 3);

	system("pause");
	return 0;
}

结构体案例2

在这里插入图片描述

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

//定义英雄结构体
struct Hero
{
	string  name;//姓名
	int age;//年龄
	string sex;//性别
};

//冒泡排序
void bubbleSort(struct Hero heroArray[], int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - i - 1; j++)
		{
			if (heroArray[j].age > heroArray[j + 1].age)
			{
				struct Hero temp = heroArray[j];
				heroArray[j] = heroArray[j + 1];
				heroArray[j + 1] = temp;
			}
		}
	}
}

//打印排序后数组中的信息
void printHero(struct Hero heroArray[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << "姓名:" << heroArray[i].name << " 年龄:" << heroArray[i].age 
			 << "性别" << heroArray[i].sex << endl;
	}
}

int main() {
	//创建数组并存放无名英雄
	Hero heroArray[5] =
	{
		{"刘备",23,"男"},
		{"关羽",22,"男"},
		{"张飞",20,"男"},
		{"赵云",21,"男"},
		{"貂蝉",19,"女"}
	};

	int len = sizeof(heroArray) / sizeof(heroArray[0]);

	cout << "排序前:" << endl;
	printHero(heroArray, len);

	//对数组进行排序,按照年龄升序排序
	bubbleSort(heroArray, len);

	//将排序后的结果打印输出
	cout << "排序后:" << endl;
	printHero(heroArray, len);

	system("pause");
	return 0;
}

内存分区模型

C++在执行时,将内存大方向划分为4个区域:

  • 代码区:存放函数体的二进制代码,由操作系统进行管理的;
  • 全局区:存放全局变量和静态变量以及常量;
  • 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等;
  • 由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

内存四区的意义:
不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。
程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
代码区

  • 存放CPU执行的机器指令
  • 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
  • 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
    全局区
  • 全局变量和静态变量存放在此
  • 全局区还包含了常量区,字符串常量和其他常量(const修饰的局部变量)也存放于此
  • 该区域的数据在程序结束后由操作系统释放
#include <iostream>
using namespace std;

//全局变量
int g_a = 10;
int g_b = 10;

//const修饰的全局变量
const int c_g_a = 10;
const int c_g_b = 10;

int main() {

	//创建普通局部变量
	int a = 10;
	int b = 10;

	cout << "局部变量a的地址是:" << (int)&a << endl;
	cout << "局部变量b的地址是:" << (int)&b << endl;

	cout << "全局变量g_a的地址是:" << (int)&g_a << endl;
	cout << "全局变量g_b的地址是:" << (int)&g_b << endl;

	//静态变量   储存在全局区
	static int s_a = 10;
	static int s_b = 10;
	cout << "静态变量s_a的地址是:" << (int)&s_a << endl;
	cout << "静态变量s_b的地址是:" << (int)&s_b << endl;

	//常量
	//字符串常量
	cout << "字符串常量的地址为:" << (int)&"hello world" << endl;

	//const修饰的变量
	//const修饰的全局变量
	cout << "const修饰的全局变量s_a的地址是:" << (int)&c_g_a << endl;
	cout << "const修饰的全局变量s_b的地址是:" << (int)&c_g_b << endl;

	//const修饰的局部变量
	const int c_l_a = 10;
	const int c_l_b = 10;

	cout << "const修饰的局部变量s_a的地址是:" << (int)&c_l_a << endl;
	cout << "const修饰的局部变量s_b的地址是:" << (int)&c_l_b << endl;

	system("pause");
	return 0;
}

在这里插入图片描述
在这里插入图片描述
程序运行后
栈区

  • 由编译器自动分配释放,存放函数的参数值、局部变量等
  • 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
#include <iostream>
using namespace std;

//栈区数据注意事项:不要返回局部变量的地址
int * func(int b)//形参数据也会放在栈区
{
	int a = 10;//局部变量,存放在栈区,栈区的数据在函数执行完后自动释放
	int b = 100;//局部变量,存放在栈区,栈区的数据在函数执行完后自动释放
	return &a;//返回局部变量的地址
}

int main() {
	int * p = func(1);
	
	cout << *p << endl;//第一次打印数据正确,因为编译器做了一次保留
	cout << *p << endl;///第二次打印数据错误,编译器不再继续保留

	system("pause");
	return 0;
}

堆区

  • 由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
  • 在C++中主要利用new在堆区开辟内存
#include <iostream>
using namespace std;

int * func( )
{
	//利用new关键字将数据开辟到堆区
	//指针本质也是局部变量,放在栈上,指针保存的数据是放在堆区
	int * a = new int(10);
	return a;
}

int main() {
	int *p = func();

	cout << *p << endl;
	cout << *p << endl;//结果不变
	system("pause");
	return 0;
}

在这里插入图片描述
new运算符

  • C++中利用new操作符在堆区开辟数据
  • 堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete
  • 语法:new 数据类型
  • 利用new创建的数据,会返回该数据对应的类型的指针
#include <iostream>
using namespace std;


int * func()
{
	//在堆区创建整型数据
	//new返回的是 该数据类型的指针
	int * p = new int(10);
	return p;
}

void test01()
{
	int * p = func();
	cout << *p << endl;
	cout << *p << endl;//堆区未释放,数据未丢失
	//释放堆区数据
	delete p;
	//cout << *p << endl;//堆区被释放,报错
}

//在堆区利用new开辟数组
void test02()
{
	//创建10个整型的数组,在堆区
	int* arr =new int[10];//10代表数组有10个元素
	//给数组赋值
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i + 100;
	}
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;
	}
	//释放堆区数组    
	//注意:释放数组要加[]才可以
	delete[] arr;
}

int main() {
	test01();
	test02();

	system("pause");
	return 0;
}

C++中的引用

引用的基本使用

  • 作用:给变量起别名
  • 语法:数据类型 &别名 = 原名
#include <iostream>
using namespace std;

int main() {
	int a = 10;
	//创建引用
	int &b = a;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	b = 100;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;//操作a和b是操作的是同一块内存

	system("pause");
	return 0;
}

引用注意事项

  • 引用必须要初始化
  • 引用一旦初始化后,就不可以更改了
#include <iostream>
using namespace std;

int main() {
	int a = 10;
	//int &b;// 错误,必须要初始化
	int &b = a;

	int c = 20;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;

	b = c;//赋值操作,而不是更改引用

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;

	system("pause");
	return 0;
}

引用做函数参数

  • 作用:函数传递时,可以利用引用的技术让形参修饰实参
  • 优点:可以简化指针修改实参
#include <iostream>
using namespace std;

//值传递
void mySwap01(int a,int b)
{
	int temp = a;
	a = b;
	b = temp;

	cout << "mySwap01中" << endl;
	cout << "\ta = " << a << endl;
	cout << "\tb = " << b << endl;
}

//地址传递
void mySwap02(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

//引用传递
void mySwap03(int &a, int &b)//等同于操作参数的别名
{
	int temp = a;
	a = b;
	b = temp;
}

int main() {
	int a = 10;
	int b = 20;

	cout << "初始值" << endl;
	cout << "\ta = " << a << endl;
	cout << "\tb = " << b << endl;

	mySwap01(a, b);//值传递,形参不会修饰实参

	cout << "mySwap01后" << endl;
	cout << "\ta = " << a << endl;
	cout << "\tb = " << b << endl;

	mySwap02(&a, &b);//地址传递,形参会修饰实参的

	cout << "mySwap02后" << endl;
	cout << "\ta = " << a << endl;
	cout << "\tb = " << b << endl;

	mySwap03(a, b);//引用传递,形参也会修饰实参

	cout << "mySwap03后" << endl;
	cout << "\ta = " << a << endl;
	cout << "\tb = " << b << endl;

	system("pause");
	return 0;
}

引用做函数返回值

  • 作用:引用是可以作为函数的返回值存在的
  • 注意:不要返回局部变量
  • 用法:函数调用作为左值
#include <iostream>
using namespace std;

int& test01()
{
	int a = 10;//存放于栈区
	return a;
}

int& test02()
{
	static int a = 10;//存放于全局区
	return a;
}

int main() {
	int &ref = test01();
	//不返回局部变量的引用
	cout << "ref = " << ref << endl;//第一次结果正确
	cout << "ref = " << ref << endl;//第二次结果错误

	int &ref2 = test02();

	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl;

	test02() = 1000;//如果函数的返回值是引用,这个函数调用可以作为左值

	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl;

	system("pause");
	return 0;
}

引用的本质

  • 本质:引用在C++内部实现是一个指针常量
#include <iostream>
using namespace std;

//发现是引用,转换为 int* const ref = &a;
void func(int& ref) 
{
	ref = 100;//ref是引用,即*ref=100
}

int main() {
	int a = 10;

	//自动转换为 int* const ref = &a;指针常量是指针指向不可改,也说明为什么引用不可更改
	int& ref = a;
	ref = 20;//内部发现ref是引用,自动帮我们转换为: *ref = 20;

	cout << "a = " << a << endl;
	cout << "ref = " << ref << endl;

	func(a);

	cout << "a = " << a << endl;
	cout << "ref = " << ref << endl;

	system("pause");
	return 0;
}

注意:C++推荐使用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作编译器都帮我们做了

常量引用

  • 作用:常量引用主要用来修饰形参,防止误操作
  • 在函数形参列表中,可以加const修饰形参,防止形参改变实参
#include <iostream>
using namespace std;

void showValue(const int &val)//加const防止误操作
{
	// val = 1000;  // 错误  加上const后变为只读,不可以修改
	cout << "val = " << val << endl;
}

int main() {
	int a = 100;
	//int &ref = 10;  //  错误,引用必须引一块合法的内存空间
	const int &ref = 10;//编译器将代码修改为 int temp =10;const int & ref = temp;

	// ref = 20;  //错误  加上const后变为只读,不可以修改
	showValue(a);

	cout << "a = " << a << endl;

	system("pause");
	return 0;
}

函数提高

函数默认参数

  • 在C++中,函数的形参列表中的形参是可以有默认值的
  • 语法:返回值类型 函数值 (参数 = 默认值)
#include <iostream>
using namespace std;

int func(int a, int b = 20, int c = 30)
{
	return a + b + c;//若传了值,则用传的数据,否则就用默认值
}

//注意事项
//如果某个位置有了默认参数,那么从这个位置往后,从左到右都必须有默认值
//声明和实现只能有一个有默认参数
/*
int func2(int a = 10,int b = 10);

int func2(int a = 10,int b = 10)   //错误,重定义默认参数
{
	return a + b + c;
}
*/
int main() {
	cout << func(10,30) << endl;

	//cout << func2(10,20) << endl;   //无法运行

	system("pause");
	return 0;
}

函数名占位参数(目前用不到)

  • C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
  • 语法:返回值类型 函数名(数据类型){}
#include <iostream>
using namespace std;

//占位参数,目前用不到
void func(int a,int)
{
	cout << "this is func" << endl;
}
//占位参数可以有默认值
void func2(int a, int = 10)
{
	cout << "this is func" << endl;
}
 
int main() {
	func(10, 10);
	//func(10)//错误,无法使用,占位参数必须填补
	func2(10);

	system("pause");
	return 0;
}

函数重载概述

  • 作用:函数名可以相同,提高复用性
  • 函数重载满足条件
    – 同一个作用域(全局域、局部域)下
    – 函数名称相同
    – 函数参数类型不同,或者个数不同,或者顺序不同
  • 注意:函数的返回值不可以作为函数重载的条件
#include <iostream>
using namespace std;

void func()
{
	cout << "func 的调用" << endl;
}
 
void func(int a)
{
	cout << "func(int a) 的调用" << endl;
}

void func(double b)
{
	cout << "func(double b) 的调用" << endl;
}

void func(int a,double b)
{
	cout << "func(int a,double b) 的调用" << endl;
}

void func(double a, int b)
{
	cout << "func(double a, int b) 的调用" << endl;
}

int main() {
	func();//调用第一个
	func(10);//调用第二个
	func(3.14);//调用第三个
	func(10, 3.14);//调用第四个
	func(3.14, 10);//调用第五个

	system("pause");
	return 0;
}

函数重载的注意事项

  • 引用作为重载条件
  • 函数重载碰到函数默认参数
#include <iostream>
using namespace std;

//引用作为重载的条件
void func(int &a)
{
	cout << "func(int &a)调用" << endl;
}

void func(const int &a)
{
	cout << "func(const int &a)调用" << endl;
}

//函数重载碰到默认参数
void func2(int a)
{
	cout << "func2(int a)调用" << endl;
}

void func2(int a,int b = 10)
{
	cout << "func2(int a,int b)调用" << endl;
}

int main() {
	int a = 10;
	func(a);
	func(10);//如果调用第一个则相当于int &a = 10 不合法,调用第二个函数,则是const int &a = 10;  合法

	//func2(10);//当函数重载碰到默认参数,出现二义性,报错,尽量避免
	func2(10, 20);//正确,只能调用有默认参数的函数

	system("pause");
	return 0;
}

类和对象

  • C++面向对象的三大特征:
    – 封装
    – 继承
    – 多态
  • C++认为万事万物都皆为对象,对象上有其属性和行为
  • 具有相同性质的对象,我们可以抽象称为类

封装

封装的意义

  • 封装是C++面向对象三大特征之一
  • 封装的意义:
    – 1、将属性和行为作为一个整体,表现生活中的事物
    – 2、将属性和行为加以权限控制
    封装意义1
  • 语法:class 类名 { 访问权限: 属性 / 行为 };
  • 例:设计一个圆类,求圆的周长
#include <iostream>
using namespace std;

const double PI = 3.14;

class Circle
{
	//访问权限
public:   //公共权限
	//属性
	int m_r;   //半径

	//行为
	double calculataZC()    //获取圆的周长
	{
		return 2 * PI * m_r;
	}
};

int main() {
	//通过圆类,创建具体的圆(对象)——————实例化
	Circle c1;
	//给圆(对象)的属性赋值
	c1.m_r = 10;

	cout << "圆的周长为:" << c1.calculataZC() << endl;

	system("pause");
	return 0;
}
  • 类中的属性和行为统称为成员
  • 属性又叫做成员属性或成员变量
  • 行为又叫做成员函数或成员方法

封装意义2

  • 类在设计时,可以把属性和行为放在不同的权限下,加以控制
  • 三种访问权限:
    – 1、公共权限 public 成员 类内可以访问,类外可以访问
    – 2、保护权限 protected 成员 类内可以访问,类外不可以访问
    – 3、私有权限 private 成员 类内可以访问,类外不可以访问
#include <iostream>
using namespace std;

class Person
{
public:	  //公共权限
	string m_Name;//名字

protected:    //保护权限
	string m_Car;//汽车

private:     //私有权限
	int m_Password;//银行卡密码

public://类内均可以访问
	void func()
	{
		m_Name = "张三";
		m_Car = "拖拉机";
		m_Password = 12345;

	}
};

int main() {
	//实例化具体对象
	Person p1;

	p1.m_Name = "李四";
	//   p1.m_Car = "奔驰"       //保护权限,类外无法访问
	//   p1.m_Password = 123;    //私有权限,类外无法访问

	system("pause");
	return 0;
}

struct和class的区别

在C++中struct和class唯一的区别就在于默认访问权限不同:

  • struct默认权限为公共
  • class默认权限为私有
#include <iostream>
using namespace std;

class C1
{
	int m_A;//默认权限为私有
};

struct C2
{
	int m_A;//默认权限是公共
};

int main() {
	C1 c1;
	//  c1.m_A = 100;    //私有权限,类外不能访问
	C2 c2;
	c2.m_A = 100;     //公共权限,类外可以访问

	system("pause");
	return 0;
}

成员属性设置为私有

优点:

  • 1、将所有成员属性设置为私有,可以自己控制读写权限
  • 2、对于写权限,我们可以检测数据的有效性
#include <iostream>
using namespace std;
#include <string>

class Person
{
public:
	//写姓名
	void setName(string name)
	{
		m_Name = name;
	}
	//读姓名
	string getName()
	{
		return m_Name;
	}
	//获取年龄
	int getAge()
	{
		return m_Age;
	}
	//修改年龄     年龄范围必须在0~150之间
	void setAge(int age)
	{
		if (age < 0 || age > 150)
		{
			m_Age = 0;
			cout << "您输入的年龄有误" << endl;
			return;
		}
		else
			m_Age = age;
	}
	//设置情人
	void setLover(string lover)
	{
		m_Lover = lover;
	}
private:
	//姓名     可读可写
	string m_Name;
	//年龄     可读可写
	int m_Age;
	//情人     只写
	string m_Lover;
};

int main() {
	Person p;
	//  p.m_Name = "张三";  //私有权限,无法类外访问
	p.setName("张三");

	cout << "姓名为: " << p.getName() << endl;

	//  p.m_Age = 18;  //私有权限,无法类外访问
	p.setAge(1000);
	cout << "年龄为: " << p.getAge() << endl;
	p.setAge(18);
	cout << "年龄为: " << p.getAge() << endl;
	
	p.setLover("苍井");
	//cout << "情人为: " << p.m_Lover() << endl;    无法访问

	system("pause");
	return 0;
}

对象的初始化和清理

  • C++中的面向对象来源于生活,每个对象都有初始设置以及对象销毁前的清除数据的设置

构造函数和析构函数

对象的初始化和清理也是两个非常重要的安全问题:

  • 一个对象或者变量没有初始状态,对其使用后果是未知
  • 同样的使用完一个对象或变量,没有及时清理,也会造成移动的安全问题
    C++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工具
  • 对象的初始化和清理工作是编译器强制要我们做的事情,因此我们不提供构造和析构,编译器会提供
  • 编译器提供的构造函数和析构函数是空实现

构造函数:主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用

构造函数语法:类名(){}

  • 1、构造函数,没有返回值也不写void
  • 2、函数名称与类名相同
  • 3、构造函数可以有参数,因此可以发生重载
  • 4、程序在调用对象时会自动调用构造,无须手动调用,而且只会调用一次

析构函数:主要作用于对象销毁前系统自动调用,执行一些清理工作

析构函数语法:~类名(){}

  • 1、析构函数,没有返回值也不写void
  • 2、函数名称与类名相同,在名称前加上符号~
  • 3、析构函数不可以有参数,因此不可以发生重载
  • 4、程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
#include <iostream>
using namespace std;
#include <string>

class Person
{
public:
	//构造函数
	//创建对象的时候,会自动调用,且只调用一次
	Person()
	{
		cout << "Person 构造函数的调用" << endl;
	}
	//析构函数
	//对象在销毁前,会自动调用析构函数,而且指挥调用一次
	~Person()
	{
		cout << "Person 析构函数的调用" << endl;
	}
};

void test01()
{
	Person p;//在栈上的数据,在test01执行完毕后,会自动释放这个对象
}

int main() {
	test01();

	Person p;//在main函数执行完时,这个对象才会被释放

	system("pause");
	return 0;
}

构造函数的分类及调用

两种分类方式:

  • 按参数分为:由参构造和无参构造
  • 按类型分为:普通构造和拷贝构造

三种调用方法:

  • 括号法
  • 显示法
  • 隐式转换法
#include <iostream>
using namespace std;

class Person 
{
public:
	Person()//无参构造函数、默认构造函数        普通构造函数
	{
		cout << "Person 的无参构造函数调用" << endl;
	}
	Person(int a)//有参构造函数                普通构造函数
	{
		age = a;
		cout << "Person 的有参构造函数调用" << endl;
	}
	//拷贝构造函数
	Person(const Person &p)
	{
		age = p.age;
		cout << "Person 的拷贝构造函数调用" << endl;
	}
	~Person()
	{
		cout << "Person 的析构函数调用" << endl;
	}
	int age;
};

//调用
void test01()
{
	Person  p1;//默认构造函数调用     此处不加()
	//Person p1();//若加,不调用class,因为编译器会认为这是一个函数的声明,不会认为在创建对象
	//括号法
	Person p2(10);//有参构造函数调用
	Person p3(p2);//拷贝构造函数调用

	cout << "p2的年龄为:" << p2.age << endl;
	cout << "p3的年龄为:" << p3.age << endl;//同p2

	//显示法
	Person p4 = Person(10);//有参构造    注:Person(10)为匿名对象
	//匿名对象特点:当前行执行结束后,系统会立即回收掉匿名对象
	Person p5 = Person(p2);//拷贝构造
	//注:不能利用拷贝构造函数初始化匿名对象     编译器会认为  Person (p3) 为  Person p3;对象声明    导致p3重定义

	//隐式转换法
	Person p6 = 10;//相当于写的是   Person p6 = Person(10);
	Person p7 = p4;//拷贝构造
}

int main() {
	test01();

	system("pause");
	return 0;
}

拷贝构造函数调用时机

C++种拷贝构造函数调用时机通常由三种情况:

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象
#include <iostream>
using namespace std;

class Person 
{
public:
	Person()
	{
		cout << "Person 的无参构造函数调用" << endl;
	}
	Person(int age)
	{
		m_age = age;
		cout << "Person 的有参构造函数调用" << endl;
	}
	//拷贝构造函数
	Person(const Person &p)
	{
		m_age = p.m_age;
		cout << "Person 的拷贝构造函数调用" << endl;
	}
	~Person()
	{
		cout << "Person 的析构函数调用" << endl;
	}
	int m_age;
};

void test01()//使用一个已经创建完毕的对象来初始化一个新对象
{
	Person p1(20);
	Person p2(p1);

	cout << "p2的年龄为:" << p2.m_age << endl;
}

//值传递的方式给函数参数传值
void dowork(Person p)
{

}
void test02()
{
	Person p;
	dowork(p);
}

//值方式返回局部变量
Person dowork2()
{
	Person p1;
	return p1;
}
void test03()
{
	Person p = dowork2();
}

int main() {
	test01();
	test02();
	test03();

	system("pause");
	return 0;
}

构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

  • 1、默认构造函数(无参,函数体为空)(空实现)
  • 2、默认析构函数(无参,函数体为空)(空实现)
  • 3、默认拷贝构造函数,对属性进行值拷贝 (值拷贝)

构造函数调用规则如下:

  • 1、如果用户定义由参构造函数,C++不再提供无参构造,但是会提供默认拷贝构造
  • 2、如果用户定义拷贝构造函数,C++不会再提供其他构造函数

规则1

#include <iostream>
using namespace std;

class Person 
{
public:
	
	Person()
	{
		cout << "Person 的默认构造函数调用" << endl;
	}
	Person(int age)
	{
		m_age = age;
		cout << "Person 的有参构造函数调用" << endl;
	}
	/*
	Person(const Person &p)
	{
		m_age = p.m_age;
		cout << "Person 的拷贝构造函数调用" << endl;
	}
	*/
	~Person()
	{
		cout << "Person 的析构函数调用" << endl;
	}
	int m_age;
};

void test01()//使用一个已经创建完毕的对象来初始化一个新对象
{
	Person p;
	p.m_age = 18;

	Person p2(p);//编译器提供默认拷贝构造

	cout << "p2的年龄为:" << p2.m_age << endl;
}

void test02()
{
	//Person p1;//有有参构造无默认构造时错误,有有参构造时,函数不会提供默认构造
	Person  p1(18);
	Person p3(p1);//编译器提供默认拷贝构造
}

int main() {
	test01();
	test02();

	system("pause");
	return 0;
}

规则2:

#include <iostream>
using namespace std;

class Person 
{
public:
	Person(const Person &p)
	{
		m_age = p.m_age;
		cout << "Person 的拷贝构造函数调用" << endl;
	}
	~Person()
	{
		cout << "Person 的析构函数调用" << endl;
	}
	int m_age;
};

void test02()
{
	//Person p;    错误
	//Person  p1(18);  错误
}

int main() {

	test02();

	system("pause");
	return 0;
}

深拷贝和浅拷贝

  • 浅拷贝:简单的赋值拷贝操作
  • 深拷贝:在堆区重新申请空间,进行拷贝操作

错误示范:

#include <iostream>
using namespace std;

class Person 
{
publicPerson()
	{
		cout << "Person 的默认构造函数调用" << endl;
	}
	Person(int age,int height)
	{
		m_age = age;
		m_height = new int(height);//须由程序员手动释放
		cout << "Person 的有参构造函数调用" << endl;
	}
	~Person()
	{
		//析构代码,将堆区开辟数据做释放操作
		if (m_height != NULL)
		{
			delete m_height;
			m_height = NULL;
		}

		cout << "Person 的析构函数调用" << endl;
	}
	int m_age;
	int *m_height;
};

void test01()
{
	Person p1(18,160);

	cout << "p1的年龄为:" << p1.m_age << "身高为:" << *p1.m_height << endl;

	Person p2(p1);

	cout << "p2的年龄为:" << p2.m_age << "身高为:" << *p2.m_height << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

错误原因:
在这里插入图片描述
两次释放同一堆区内存空间,第二次为非法操作

利用深拷贝修改
在这里插入图片描述

#include <iostream>
using namespace std;

class Person 
{
public:
	
	Person()
	{
		cout << "Person 的默认构造函数调用" << endl;
	}
	Person(int age,int height)
	{
		m_age = age;
		m_height = new int(height);//须由程序员手动释放
		cout << "Person 的有参构造函数调用" << endl;
	}
	//自己实现拷贝构造函数, 解决浅拷贝带来的问题
	Person(const Person &p)
	{
		cout << "Person 的拷贝构造函数调用" << endl;
		m_age = p.m_age;
		//m_height = p.m_height;    编译器默认实现就是此行代码
		//深拷贝操作
		m_height = new int(*p.m_height);
	}
	~Person()
	{
		//析构代码,将堆区开辟数据做释放操作
		if (m_height != NULL)
		{
			delete m_height;
			m_height = NULL;
		}

		cout << "Person 的析构函数调用" << endl;
	}
	int m_age;
	int *m_height;
};

void test01()
{
	Person p1(18,160);

	cout << "p1的年龄为:" << p1.m_age << "身高为:" << *p1.m_height << endl;

	Person p2(p1);

	cout << "p2的年龄为:" << p2.m_age << "身高为:" << *p2.m_height << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

初始化列表

  • 作用:C++提供了初始化列表语法,用来初始化属性
  • 语法:构造函数():属性1(值1),属性2(值2)…{}
#include <iostream>
using namespace std;

class Person
{
public:
	//传统初始化操作
	/*
	Person(int a, int b, int c)
	{
		m_A = a;
		m_B = b;
		m_C = c;
	}
	*/

	//初始化列表
	Person(int a,int b,int c) :m_A(a), m_B(b), m_C(c)
	{

	}

	int m_A;
	int m_B;
	int m_C;
};

void test01()
{
	//Person p(10, 20, 30);
	Person p(30,20,10);
	cout << "m_A = " << p.m_A << " m_B = " << p.m_B << " m_C = " << p.m_C << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

注意:冒号位置
类对象作为类成员

  • C++类中的成员可以时另一个类的对象,我们称该成员为对象成员
#include <iostream>
using namespace std;
#include <string>

class Phone
{
public:
	Phone(string pname)
	{
		m_Pname = pname;
		cout << "Phone的构造函数调用" << endl;
	}
	~Phone()
	{
		cout << "Phone的析构函数调用" << endl;
	}
	//手机品牌名称
	string  m_Pname;
};
class Person
{
public:
	Person(string name, string pname) :m_name(name), m_phone(pname)
	//相当于Phong m_phone = pname   隐式转换法
	{
		cout << "Person的构造函数调用" << endl;
	}
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}

	//姓名
	string m_name;
	//手机
	Phone m_phone;
};

void test01()
{
	Person p("张三", "苹果MAX");
	cout << p.m_name << "拿着:" << p.m_phone.m_Pname << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

当其他类对象作为本类成员,构造时先构造类对象,再构造自身
当其他类对象作为本类成员,析构时先析构自身,再析构对象

静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员

静态成员分类:

  • 静态成员变量:
    – 所有对象共享同一份数据
    – 在编译阶段分配内存
    – 类内声明,类外初始化
  • 静态成员函数:
    – 所有对象共享同一个函数
    – 静态成员函数只能访问静态成员变量
#include <iostream>
using namespace std;
#include <string>

class Person
{
public:
	//静态成员函数
	static void func()
	{
		m_a = 100;//静态成员函数可以访问静态成员变量         共享的,所有成员公用同一参数
		//  m_b = 200;    错误,静态成员函数不可以访问非静态成员变量     因为编译器不确定修改的是哪个对象的m_b属性
		cout << "static void func的调用" << endl;
	}
	static int m_a;//静态成员变量
	int m_b;//非静态成员变量
private:
	static void func2()
	{
		cout << "static void func2的调用" << endl;
	}
};

int Person::m_a = 0;

//两种访问方式
void test01()
{
	//通过对象访问
	Person p;
	p.func();

	//通过类名访问
	Person::func();

	//Person::func2();    错误,类外不可以访问私有静态成员函数
}

int main() {
	test01();

	system("pause");
	return 0;
}

C++对象模型和this指针

成员变量和成员函数分开储存

  • 在C++中,类内的成员变量和成员函数分开储存
  • 只有非静态成员变量才属于类的对象上

空对象占用内存空间为1

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

class Person
{

};

//两种访问方式
void test01()
{
	Person p;

	//空对象占用内存空间
	//C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
	//每个空对象也应该有一个独一无二的内存地址
	cout << "size of p=" << sizeof(p) << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

成员变量和成员函数分开储存

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

class Person
{
	int m_a;   //非静态成员变量
	static int m_b;    //静态成员变量    不属于类对象上
	void func()//非静态成员函数      不属于类对象上
	{  }
	static void func2() {}//静态成员函数        不属于类对象上
};

int Person::m_b = 0;

void test01()
{
	Person p;

	cout << "size of p = " << sizeof(p) << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

this指针概念

  • this指针指向被调用的成员函数所属的对象
  • this指针是隐含每一个非静态成员函数内的一种指针
  • this指针不需要定义,直接使用即可
  • this指针的用途:
    – 当形参和成员变量同名时,可用this指针来区分
    – 在类的非静态成员函数中返回对象本身,可使用return * this
#include <iostream>
using namespace std;
#include <string>

class Person
{
public:
	Person(int age)
	{
		this->age = age;//解决名称冲突      this指针指向被调用的成员函数所属的对象
	}
	Person & PersonAddage(Person &p)
	{
		this->age += p.age;
		return *this;
	}
	int age;
};

void test01()
{
	Person p1(18);

	cout << "p1的年龄为:" << p1.age << endl;
}

//返回对象本身用*this
void test02()
{
	Person p1(10);
	Person p2(10);

	//链式编程思想
	p2.PersonAddage(p1).PersonAddage(p1).PersonAddage(p1);

	cout << "p2的年龄为:" << p2.age << endl;
}

int main() {
	test01();
	test02();

	system("pause");
	return 0;
}

空指针访问成员函数

  • C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
  • 如果用到this指针,需要加以判断保证代码的健壮性
#include <iostream>
using namespace std;
#include <string>

class Person
{
public:
	void showclassname()
	{
		cout << "this is Person class" << endl;
	}
	void shoePersonage()
	{
		if (this == NULL)//提高代码健壮性
		{
			return;
		}
		cout << "age = " << this->m_age << endl;
	}
	int m_age;
};

void test01()
{
	Person *p = NULL;

	p->showclassname();
	//p->shoePersonage();    错误,因为传入的指针为空
}

int main() {
	test01();

	system("pause");
	return 0;
}

const修饰成员函数

常函数

  • 成员函数后加const后我们称这个函数为常数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数
#include <iostream>
using namespace std;
#include <string>

class Person
{
public:
	void showPeson() const//常函数
	{
		this->m_b = 100;
		//  this->m_a = 100;   this指针本质是指针常量,指针的指向是不可以修改的
		//成员函数后的const实际上修饰的是this指针,让指针指向的值也不可以修改
		//this = NULL;    this指针不可以修改指针的指向

	}
	void func()
	{
		m_a = 100;
	}

	int m_a;
	mutable int m_b;//特殊变量,即使在常函数中,也可以修改这个值,加关键字mutable
};

void test01()
{
	Person p;
	p.showPeson();
}

//常对象

void test02()
{
	const Person p;//在对象前加const ,变为常对象
	// p.m_a = 100;   
	p.m_b = 100;//特殊变量,即使在常d对象下,也可以修改这个值

	//常对象只能调用常函数
	p.showPeson();
	//p.func();   错误,常对象不可以调用普通成员函数,因为普通成员函数可以修改属性
}

int main() {
	test01();

	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值