四、基本数据类型和计算(三)

1、枚举变量

1)通过案例体现枚举类型的作用

​ 假设要为我们的游戏装备设置稀有度属性,应该如何设计

装备级别 变量名
普通 normal
高级 high
稀有 rare
史诗 epic
传说 legend
神话 myth

不使用枚举变量,使用常量方式设置

#include  <iostream>
#define Normal 0  //普通装备
#define High 1   //高级装备
#define Rare 2   //稀有装备
#define Epic 3   //史诗装备
#define Legend 4   //传说装备
#define myth  5   //神话装备

int main()
{
	short weaponLv;
	
	short weaponALv = Rare;  //稀有
	short weaponBLv = myth;  //神话

	std::cout << "装备A的等级为:" << weaponALv << std::end;;
	std::cout << "装备B的等级为:" << weaponBLv << std::endl;

}

2)枚举变量定义及声明

​ 计算机中没有这种类型,我们自定义一种数据类型,就叫做枚举类型

定义 enum class 类型名称:基本类型{选项1,选项2};
声明 类型名称 变量名称;
示例 如下

注:基本类型只能是整数类型,如果不写默认为int类型,整数类型用来说明大括号中定义的变量是什么类型。

//通过枚举类型设置装备的稀有程度
#include <iostream>
int main() {

	enum class EquipLv : int {     //可以将int替换为其他整数类型,如float
		normal = 10,   armyA = normal,//普通        //若不初始化,默认为0
		high,          armyB = high,//高级          //从上之下自动递增,此处high为11
		rare,          armyC = rare,//稀有
		epic,          armyD = epic,//史诗
		legend,        armyE = legend,//传奇
		myth = 100,    armyS = normal//神话
	};

	EquipLv weaponAlv{ EquipLv::normal }; //定义装备A等级
	EquipLv weaponBlv{ EquipLv::myth }; //定义装备B等级

	short diff = (int)weaponAlv - (int)weaponBlv;       //如果不强制类型转化,无法直接进行计算
	std::cout << "weaponAweaponB装备的等级差为:" << diff << std::endl;

	weaponAlv = EquipLv::rare; //重新赋值。修改装备A的等级
	std::cout << "装备A的等级修改为:" << int(weaponAlv)<<std::endl;
}

2)枚举类型注意点

①枚举类型可以提高代码的可读性和安全性

②枚举类型默认是int类型

③枚举类型成员只能是整数类型

④枚举类型和其他类型转化需要强制转化

⑤默认情况下,枚举类型的下一项的初始值是上一项的初始值+1

2、自定义变量名称

将C/C++中已有的变量进行改名,可以将一些特别长的变量名进行改名

语法 含义 缺点
#define A TypeName 以后代码中的A可以被替换为TypeName 简单替换
typedef TypeName A; 以后TypeName类型的名字可以用A替换 不直观
using A=TypeName; 以后TypeName类型的名字可以用A替换 可以实现一些新特性

#include <iostream>
#define 整数 int   //自定义变量名称方法一
#define elong long ////自定义变量名称方法一,将long替换为elong

int main() {
	整数 num{ 100 };    //编译器编译时,会将所有的"整数"替换为int
    
	typedef unsigned xxx;      //自定义方法名称二,即将unsigned类型替换为xxx
	xxx A{200};
    
    using ellong = long long;   //自定义变量名称方法三,将long long替换为ellong,
	ellong a{50};
    
    using elllong = elong elong; //此时的一个long已通过elong替换

	std::cout << num << char(10);
	std::cout << A << char(10);
    std::cout << a << char(10);

}

3、命名空间

1)命名空间定义

​ 为了将需要用的东西放到一起,例如: 粮食仓库::大米;粮食仓库:小麦

namespace namespace_name {
   // 代码声明
}

2)命名空间使用

使用方式 语法 备注
方式一 std::cout 使用限定符::
方式二 using std::cout;cout<<"再不用std"; 使用using,只有cout不需要写命名空间std
方式三 using namespace std; 命名空间所有内容都可进行使用,不推荐
//命名空间的定义和使用
#include <iostream>

namespace lGame {
	int HP{ 1000 };
	int MP{ 1000 };
	int lv{ 1 };
	namespace Weapon {              //命名空间的内嵌定义
		int damage{ 3000 };
		namespace WeaponInfo {
			int lv = lGame::lv;
		}
	
	}
}

int main() {
	using std::cout;       //命名空间第一种使用方式
	using namespace std;   //命名空间第二种使用方式
	using lGame::HP;       //命名空间第三种使用方式
    
    std::cout<<"用户血量为"<<lGame::HP<<std::endl;   //命令空间的使用
    std::cout<<"用户血量为"<<HP<<std::endl;

	int c = lGame::Weapon::damage;        //命名空间内嵌使用
	cout << c;         //此时不需要在写cout

}

3)命名空间注意事项

①不能将命名空间定义放在函数体内

②可以在一个命名空间内嵌入另一个命名空间

③子级命名空间调用父级命名空间依然需要限定符::

4、变量的生命周期

​ 变量的声明周期,本质上为内存的生命周期。即内存的申请和释放

#include <iostream>

int a{ 100 };      //没有在代码块内,属于全局变量,程序结束则变量结束
int main()
{
	int a{ 160 };
	{
		int a{ 350 };     //在代码快中可以用::a来调用全局变量a{100};
		{
			char a = 'A';
			std::cout << a<<std::endl;  //输出A
			std::cout << ::a << std::endl; //输出100
		} 
		std::cout << a << std::endl;  //输出350  //变量就近往上原则,声明周期原则,通常找距离它最近的值
	}
	std::cout << a  <<std::endl;  //输出160

}

1)注意事项

①代码块中的变量的生命周期从声明开始,知道这个代码块结束

②声明在代码开始前的变量叫做全局变量,全局变量的生命从程序运行开始,知道程序退出

③在变量名冲突的情况下,采用就近原则

④要访问名称冲突的全局变量,可以使用限定符::来访问

⑤变量哪里用哪里声明

5、位运算之异或运算

1)异或运算关系:相同为0,不同为1

2)作用:加解密

3)异或运算最大特征:具有还原功能,只要其中有一个值发生了变化,都可通过相互异或检测出来。

即a^b=c; b^c=a; c^a=b;

4)案例:

​ 麟江湖是一个单机游戏,其中变量diamond代表钻石,变量vip_exp代表累计钻石消费数。设计一个算法,使得能够发现,用户使用单机修改器修改了钻石或者累计钻石数这样的做必须行为。

思路:将钻石diamond和累计消费数vip_exp放在a、b的位置,只要将两个值进行异或操作生成C,只要使用C和其中任何一个值异或计算,就可判断出第三个值是否发生改变,进而检测出用户有无作弊

#include <iostream>

int main() {
	unsigned int diamond{ 6000 }; //钻石数量
	unsigned int vip_exp{ 80000 }; //VIP充值经验
	unsigned xbase = diamond ^ vip_exp; 

	std::cout << "修改钻石数量:";
	std::cin >> diamond;
	std::cout << "修改累计消费:";
	std::cin >> vip_exp;
	//模拟检测
	unsigned realDiamond = xbase ^ vip_exp;
	unsigned realvip_exp = xbase ^ diamond;
	std::cout << "你应该的钻石数量为:" << realDiamond << std::endl;
	std::cout << "你应该的累计消费为:" << realvip_exp << std::endl;

}

只要修改一个值,就可还原出来原来的数据;如果修改两个值,值虽然不会还原出来,但是也可以确认用户作弊了

7、自定义数据类型(结构体)

​ 自己创建数据类型,解决基本数据类型解决不了的问题。

基本数据类型问题:假如要创建一个汽车管理系统,要定义多个品牌的车,每个品牌的属性都不一样,若只用基本数据类型,就需要将每种品牌的车都进行定义,很麻烦

#include <iostream>

int main()
{
	int wheel {19};
	unsigned price{ 100000 };
	char logo{ 'B' };
	unsigned gls{ 100 };

	std::cout << "车辆商标:" << logo << "  车轮大小:" << wheel << "  车辆售价:" << price << std::endl;

	int wheelA{ 20 };
	unsigned priceA{ 900000 };
	char logoA{ 'C' };
	unsigned glsA{ 200 };

	std::cout << "车辆商标:" << logoA << "  车轮大小:" << wheelA << "  车辆售价:" << priceA << std::endl;
}

1)结构体定义及使用

//结构体的定义方法
struct 名称
{
    类型 名称;
}
//结构体类型使用
结构体名称 变量名{初始化值};

//简单案例
struct CAR      //结构体定义
{
		char logo{ 'X'};       
		unsigned short whell{ 19 };
		unsigned price{ 90000 };
};

CAR carA{'A',20,80000} //结构体变量初始化
std::cout<<carA::log<<std::endl;  //结构体变量的使用

3)结构体使用

#include <iostream>

int main() {
	struct Car            //结构体类型的定义
	{
		char logo{ 'X' };
		unsigned short whell{ 19 };
		unsigned price{ 90000 };
	};

	Car carA{ 'X',25,5000000 };    //结构体类型变量的定义及初始化
	Car carB{ 'Y',30,4000000 };
	Car carC{ 'Z',15,200000 };

	//结构体变量的使用
	std::cout << "A车辆logo:" << carA.logo << ",A车辆轮子:" << carA.whell << ",A车辆售价:" << carA.price << std::endl;
	std::cout << "B车辆logo:" << carB.logo << ",B车辆轮子:" << carB.whell << ",B车辆售价:" << carB.price << std::endl;
	std::cout << "C车辆logo:" << carC.logo << ",C车辆轮子:" << carC.whell << ",C车辆售价:" << carC.price << std::endl;
}

2)结构体的本质

①结构体的本质是按照我们自己定义的方式定义一块连续的内存的结构

②声明一个结构体变量的本质是向计算机申请一块内存,而这块内存的大小,至少是我们定义的结构成员需要占用的内存之和(某些情况内存会虚高)

③使用结构体,则是按照我们定义好的方式从这块内存读取和写入数据

8、案例:设计游戏角色数据

​ 为麟江湖游戏设计角色的基本属性,角色包括一下属性:

①等级(1-100级)

②门派(武当、峨眉、少林、葵花、唐门)

③武器(0-15阶,0-15强化),护甲(0-15阶,0-15强化),首饰(0-15阶,0-15强化)

④经验值 ⑤生命值 ⑥生命最大值 ⑦内力值 ⑧内力最大值 ⑨坐标 ⑩金币 ⑪ 钻石 ⑫ 幸运值 ⑬ 累计消费

#include <iostream>

//门派定义
enum class SCHOOL :char {
	wudang,
	emei,
	kuihua,
	tangmen,
	shaolin,
};

//装备定义
struct Equip
{
	unsigned char lv{ 0 }; //装备等级
	unsigned char ev{ 0 }; //装备强化等级
};

//角色状态定义
struct RoleState
{
	int value{ 1000 }; //角色生命值
	unsigned maxValue{ 1000 }; //角色最大生命值
};

//角色定义
struct Role {
	unsigned char lv{ 1 }; //角色等级
	SCHOOL school{ SCHOOL::tangmen };  //门派
	Equip  weapon{ 1,1 }; //武器等级、强化等级
	Equip  army{ 1,10 };  //布甲等级、强化等级
	Equip neck{ 1,10 };    //
	long long exp{ 0 };
	RoleState HP{ 1000,1000 }; //角色血量、最大生命值
	RoleState MP{ 1000,1000 }; //角色蓝量、最大蓝量
	unsigned x{ 500 }; //横坐标
	unsigned y{ 500 }; //纵坐标
	unsigned Money{ 1000 }; //金币数
	unsigned Diamond{ 100 }; //钻石数
	unsigned char luck{ 2 };//幸运值
	unsigned vip_exp{ 0 }; //充值经验

};

int main() {

	Role user;  //定义结构体时,已完成初始化,此处可以不用初始化
	std::cout << "生命:" << user.HP.value << "/" << user.HP.maxValue << std::endl;
	std::cout << "内力:" << user.MP.value << "/" << user.MP.maxValue << std::endl;
	std::cout << "坐标:【" << user.x << "】【" << user.y << "】" << std::endl;

}

ser.school = SCHOOL::wudang; //修改角色门派