目录
头文件:
#符号之后的都是预处理语句,会优先在实际编译发生之前处理,所以叫做预处理
//include是找到一个<>文件并将该文件的所有内容都拷贝到现在的文件内, 这些文件通常叫做头文件
#include <iostream> //input output stream 输入输出数据流头文件
#include <string> //字符串头文件
头文件路径包含
#include "Head.h"
//有些头文件使用<>有些使用""
//编译程序时有两种不同的含义,需要告诉编译器包含文件的路径是什么
//如果包含文件是在其中一个文件夹里,可以使用<>告诉编译器搜索包含路径文件夹
//而""通常用于包含相对于当前文件的文件
//例如有个log.h在cpp文件所在目录的上层目录下,可以使用../返回当前文件的上级目录 #include "../log.h"这是相对于当前文件的路径
//而<>就没有相对于当前文件的了,只需要在其中一个包含目录里面就行了
//#include "iostream"也是完全可以的
//<>只用于编译器包含路径,""引号可以做一切,通常只用它在相对路径,主要还是<>尖括号 //iostream没有包含任何后缀,它实际上是一个文件,只是没有扩展名
// (这是写C++标准库的人决定这么做的,将C++标准库与C标准库进行区分)
//C标准库通常会有.h扩展,例如:#include <stdlib.h>,但是C++文件没有
//这是一种区分C++标准库和C标准库的方法,看它们是否有.h扩展
编译器行为
//项目中的每一个cpp文件都会被编译,但头文件不会被编译,因为在预处理时包含进来了
//cpp文件被编译的时候,包含进来的文件一起被编译了,因此有了一堆将要被编译的cpp文件
//分别被编译器编译,每一个cpp文件都被编译成了一个object file(目标文件),用vs生成的文件后缀是.obj
//有了这些生成的独立的obj文件之后,就需要把这些文件合并成一个执行文件
//这就需要链接(link),它就是将所有的obj文件黏合到一起,将所有的obj文件合并成一个exe文件 //编译单独一个文件不会进行链接
//默认情况下vs会输出构建文件到debug文件夹,会有obj文件等
//当构建整个项目的时候就会进行链接,在解决方案目录下的debug文件夹下生成exe文件
//当前main函数cpp文件声明函数,其它cpp文件定义函数时
//编译器会无条件相信声明函数的存在,链接器会找到正确的函数定义在哪里(cpp文件),将函数定义导入到函数中让main调用
头文件保护符(监督)
原因:如果不小心多次包含了一个文件并转换为一个翻译单元会得到duplicate复制错误,会复制粘贴整个头文件多次
例如:当前1.h被包含在2.h,而main同时包含了1.h,2.h,相当于包含了两次1.h,会出现报错
而#pragma once的作用就是识别它是否被包含了多次,这种情况下不会报错,阻止多次包含
#pragama once
含义:监督这个头文件,阻止单个头文件多次被包含,并转换为单个翻译单元
这并不妨碍将头文件放到程序的多个位置,而只是说放在一个翻译单元一个cpp文件
#pragama once
另外一种方法
#ifndef _HEAD_H
//ifndef后面是需要检查的符号
#define _HEAD_H
#endif
//ifndef后面是需要检查的符号
//这是检查是否有一个叫做_HEAD_H的符号被定义了
//如果没有定义将继续在编译中包含后续程序代码到endif结束
//如果检查到已经被定义了,则直到endif结束,中间所有内容都不会被包含
这种头文件保护符(监督,警卫)的东西在过去被广泛使用,现在有新的更简洁的pragma once经常使用
命名空间
关键词:namespace
string,cout,cin,endl等需要用到标准命名空间
using namespace std;//std == standard 标准命名空间
基础(声明与定义)
声明 == 告诉编译器这个函数的存在(就是取名字)
定义 == 告诉编译器具体含义或者具体值,(函数体具体做了什么)(就是有什么作用)
变量
//编程的大部分内容实际上都是在使用数据,使用任何想要改变的数据,读.写.存储数据等,变量就是所操作的数据
//声明一个变量意味着为这个变量预先分配了一些内存
//变量为我们的程序提供有名字的可操作的储存空间
//变量类型决定变量大小和内存布局,以及可应用于该变量的操作集
char myCharacter; //char是character的缩写,是单个字符
初始化的含义:
这个变量没有被赋值,当声明一个变量的时候,上一个程序的内存会被保留下来,也就是说这个变量包含垃圾数据
所以需要覆盖它,给它初始化
myCharacter = 'y';
//现在它的储存空间包含了一个字符,没有多余的储存空间容纳多个字符
int myInt;
myInt = 13;
float myFloat = 7289;// 7289 = 7.289e3 //e3为10的3次方 //doube > float
// 0 0.0 0.0000都是零,计算机视其真值为false, 0.0000001真值为true, -1 ,1 真值为true
不同的初始化方式:
int a(1);
int b = 13;
常量
关键词:const
含义:常量也就是我们熟知的阿拉伯数字之类的,其含义已经被定死了,也就是说1就是1,不能成为2
而自定义常量:也就是硬编码变量,声明并初始化为一个常量,其值不可修改,否则会编译错误
int a = 1;//这是全局变量,可以作用与所有
//全局变量,可以直接在函数中使用
const float PI = 3.14159;//这就是常量
//这里的PI就相当于我们定义了一个额外的数字,赋予了含义,所以其他地方不可以再修改
const float WalkSpeed = 500.f//.f代表浮点型,所以是浮点型常量
int main(){}
左移运算符和右移运算符
左移运算符: <<
向左输出数据,从右向左执行程序
cout输出:打印输出
将字符串HelloWorld推送到cout数据流中,然后打印到终端
std::cout << "HelloWorld" << std::endl;
右移运算符: >>
向右存储数据,从左向右执行程序
cin输入:从键盘获取
std::cin >> getchar;
cin类似cout命令,cin命令是从键盘获取数据,>>代表数据流流动方向
这些运算符,叫做重载运算符,类似于函数;
字符串:String
C风格字符串:
在C语言中字符串是由\0结尾的字符数组
C语言中没有字符串类型,只有字符数组,且必须以空字符即\0结尾,以告诉程序停止在数组中查找
char hua[4] = { 'R','e','d','\0' };//此为C风格字符串,实际为字符数组
char hua[4] = { "Red" };//双引号为单引号的简写,会自动在最后放置一个空字符;
C++字符串:
关键词:String(严格意义上来说是C++的自定义类型)
//C++字符串类型,内部是拥有空字符的字符数组,这是它的工作方式
//C++中的string对象为自定义类型,结尾也有一个隐式的空字符
//C++字符串不能作为数据类型使用,必须包含C++标准库中的内容,也就是<string>头文件 //string对象是标准命名空间的一部分,所以是标准字符串或者std::string
//双引号加上包围的文本会创建一个字符串字面量,字符串字面量就是你可以赋值给字符串的值
//所以初始化字符串的内容必须是双引号
std::string str = "Red";
string first = "Allen";
string last("Jones");
cout << first << " " << last << std::endl;//output(Allen Jones)
string对象能够更轻松的连接字符串,用一个字符串连接另一个字符串来创建更长的字符串
string myStr = "Druid";
string& myRef = myStr;//&为引用,会改变原本的值,相当于变量的别名,本质上是一个东西
cout << myStr << endl;//输出Druid
cout << myRef << endl;//输出Druid
myRef += " Mechanics";
cout << myStr << endl;//输出Druid Mechanics
cout << myRef << endl;//输出Druid Mechanics
数组
含义:值的容器,只能保存所有数据类型相同的值
声明:
int myIntArray[3];//声明
myIntArray[0] = 1;//定义|初始化
myIntArray[1] = 2;
myIntArray[2] = 3;
double myDubArray[] = { {3.14159},{2.71828} };//初始化
数组初始化:
int main()
{
int MyIntArray[10];//声明
for (int i = 0; i < 10; i++)
{
MyIntArray[i] = 1;
cout << MyIntArray[i] << endl;
}
//数组初始化列表:
int MyArray[5]={1,2,3,4,5}
}
增量运算符
//int i = 1.5f 的情况,相当于floor,浮点型转整数型不是四舍五入而是直接丢弃小数
int i = 1;
i += 1;//i=2;
i -= 1;//i=1;
i *= 6;//i=6;
i /= 3;//i=2;
i %= 1;//i was 2;now i=0;
++i;//类似于函数,input i返回i+1;前自增符 //i先加1,返回i
i++;//返回i ,执行此行代码之后再i+1; 先返回结果后修改变量; 故称后自增符(相对于此完整的一行)
//前自增符先计算后返回i,后自增符先返回i后计算
i = 1;
std::cout << ++i << std::endl;
std::cout << i << std::endl;//返回结果都为2
std::cout << i++ << std::endl;//返回结果为2,然后修改变量,执行下一行代码//在同一行先输出再计算
//先输出i,再计算i+1
std::cout << i << std::endl;//返回结果为3在不同行值已经被改变
//int j = ++i; int j = i++; //总是先执行i自身前面的内容,再返回后面的内容
逻辑工具
逻辑工具://或,与和真值表
//与:&&
//或:||
//非: !
//等于: == (一个等于号为赋值)
if (i < k || i = k){}
if ((i <= k && i < j) && j == ){}
条件判断语句
//尽量避免使用条件语句
//当有了条件语句所产生的分支,基本上就是在内存和分支之间跳跃(实际过程更复杂)
//检查条件,然后跳转到内存的不同的地方并从这里开始执行指令
//这意味着if语句和分支通常有比较大的开销,建议不用或少用,许多优化的代码将特意避免分支
//if-if else 由上到下依次判断,判定为真则输出并忽略以下判定
if语句:if(条件){}
if else语句:if(条件){}else{}
int x = 5; bool comparisonResult = x == 5;//这里==操作符这样运行的原因是因为它在C++标准库中被重载了
//这里就是判断x是否等于5,返回true或者false
//bool就像写一个函数,接受两个整数参数然后检查这两个整数的内存以确保它们是相等的,然后返回true
if(comparisonResult)//这里等同于comparisonResult == true,一般简写
{}
特殊的else if语句: 实际上只是语法上的小技巧,并不是一个额外的独立的判断语句
else if(){}等同于
else
if(){}
实际上是一种巧妙地隐藏语法,两个分开的语句,只是将两个语句放在了一行而已
if()
{
}
else
{
if()
{
cout << "hello" << endl;
}
}
else if不是C++的关键词,只是先else再if
switch():
//if__else if语句需要一个一个检查,导致运行缓慢
//Switch只需要检查一个条件,所以高效
int Selection = 4;
switch (Selection)
{
case 1:
cout << "One" << endl;
break;
case 2:
cout << "Two" << endl;
break;
case 3:
cout << "Three" << endl;
break;
case 4;
cout << "Four" << endl;
break;
default:
cout << "lnvoid choice!" << endl;
break;
} //若没break,会直接进入下一个case继续执行下一个的代码
枚举
枚举是自定义数据类型
声明与定义:enum 枚举项目名{枚举项}
枚举中的项就类似于各个模式,是一个集合,每个枚举项代表一个模式,本质上还是整数
说一个例子:射击游戏中的切换主副武器就可以看成是枚举,
enum 武器模式{
主武器 = 1;
副武器 = 2;
近身武器 = 3;
}
有点像数组定义:看成是一个一行的语句,枚举中的项就类似于数组成员
以enum PlayerStatus{}为例:实际上并不是初始化或声明一个新变量,而是名为PlayerStatus的枚举类型
PlayerStatus将这些定义为选项
//定义后可以创建枚举,基本就是PlayerStatus的一个实例
//就像创建一个PlayerStatus类型状态的变量
//作为枚举变量声明类型使用
//枚举条目的本质是整型常量
//枚举项自动给定默认值,从第一项为开始,然后下一项是它的值+1
enum PlayerStatus {//定义了PlayerStatus这个枚举的项目
//PlayerStatus将这些定义为选项
PS_Crouched,
PS_Standing,
PS_Running,
PS_Sprinting
};//这是一个语句
//定义后可以创建枚举,基本就是PlayerStatus的一个实例
//就像创建一个PlayerStatus类型状态的变量
PlayerStatus status = PS_Crouched;//作为枚举变量声明类型使用
//声明一个名为status的枚举变量,值必须是定义过的枚举项之一
switch (status)//switch判断
{
case PS_Crouched;
cout << "Crouched" << endl;
break;
case PS_Standing;
cout << "Standing" << endl;
break;
case PS_Running;
cout << "Running" << endl;
break;
case PS_Sprinting;
cout << "Sprinting" << endl;
break;
efault:
cout<<"lnvalid chaice!"
break;
}
//把所有东西放同一行也是可以的
enum GameState{GS_Paused,GS_Play};
//将第一个初始化为1,后面的同样默认为前面的+1;
enum ItemStatus{IS_PicvedUp = 1,IS_Drcopped,IS_Eqvipped};
//可以用不同的值初始化每个枚举常量
enum Gurrency {Copper = 1,Silver = 100,Gold = 1000};
//可以有两个常数名相同的枚举
enum PlayerStatus{PS_Crouched,PS_Standing,PS_Walking,PS_Running};
enum MovementStatus{MS_Crouched,PS_Running};
PlayerStatus status = PS_Crouched;
//区分两个常数明相同的枚举,需调用所引用枚举的名字,例:
status = PlayerStatus::PS_Running;
status = MovementStatus::PS_Running;
//status的变量类型是PlayerStatus,不接受MovementStatus类型的枚举变量
枚举与switch,引用的例子
enum PlayerStatus
{
PS_Running,
PS_Walking,
PS_Crouching
};
const float RunSpeed = 800.f;//.f代表浮点型,所以是浮点型常量
const float WalkSpeed = 500.f;
const float CrouchSpeed = 350.f;
//全局常量,可以直接在函数中使用
void UpdateMovementSpeed(PlayerStatus P_Status, float& speed);
int main()
{
float MovementSpeed;
PlayerStatus status = PS_Walking;//定义枚举类型的变量
UpdateMovementSpeed(status, MovementSpeed);//&引用修改变量本身
cout << "MovementSpeed=" << MovementSpeed << endl;//输出500.f
system("pause");
}
void UpdateMovementSpeed(PlayerStatus P_Status, float& speed)
{
if (P_Status == PS_Running)
{
speed = RunSpeed;
}
else if (P_Status == PS_Walking)
{
speed = WalkSpeed;
}
else if (P_Status == PS_Crouching)
{
speed = CrouchSpeed;
}
}
//switch式
void UpdateMovementSpeed(PlayerStatus P_Status, float& speed)
{
switch (P_Status)
{
case PS_Running:
speed = RunSpeed;
break;
case PS_Walking:
speed = WalkSpeed;
break;
case PS_Crouching:
speed = CrouchSpeed;
break;
}
}
循环
while循环与do whlie循环:
whlie(条件){循环体} 先判断再循环
do{循环体}while(条件) 先循环再判断,能确保执行一次
int i = 0;
int j = 1;
while (i < j)//先判断再循环
{ i++; };//while循环,判断条件进入循环
do { i++; } //先循环再判断
while (i < j);//do while循环,确保执行一次循环;循环内需要有能够满足跳出循环的条件;否则会无限循环
for循环:
用的最多的循环了
for(条件){循环体}
条件中定义了循环方式
流程控制语句:
break 直接跳出整个循环
continue 跳过本次子循环后续内容,直接进入下一次循环
//结束此次循环,进入下一次循环重新判断条件进行循环
for (int i = 0; i < 5; i++){
if (i % 2 == 0)
continue;//满足条件是跳出本次循环进入下一次循环
std::cout << "hello" << std::endl;
}
return 返回值
return 0; 会直接返回给函数,跳出函数,包括main函数