C++基础
循环
- for
1
2
3
4for (int i=0; i<5;i++)
{
printf();
} - while
1
2
3
4
5
6int i=0;
while (i<5)
{
printf();
i++;
}
控制流
- continue 执行后进入这个循环的下一次迭代
1
2
3
4
5
6for (int i=0; i<5;i++)
{ if (i<2)
continue;
std::cout << i << std::endl;
}
std::cin.get(); - break 执行后跳出循环即终止循环
1
2
3
4
5
6for (int i=0; i<5;i++)
{ if (i<2)
break;
std::cout << i << std::endl;
}
std::cin.get(); - return 返回值
指针
- 指针是一个数字,一个保存内存地址的数字,逆向引用可以改变地址储存的数据
1
2
3
4
5
6
7int* ptr = nullptr;
int var = 8;
ptr = &var; //ptr问var,伙计你的地址让我看看
*ptr = 10; //对ptr储存的地址写入数据10
std::cout << var << std::endl;
//此时var值为10
std::cin.get(); - 开辟一块内存,并返回指向那块内存开始的指针
1
2
3
4
5
char* buffer = new char[8]
memset(buffer,0,8); //用指定的数据填充一个内存块
//参数: 内存块开始的指针, 填充数据,内存大小
delete[] buffer; - 双指针
1
2
3
4
5
6
7
8
9
10char* buffer = new char[8]
memset(buffer,0,8); //用指定的数据填充一个内存块
//参数: 内存块开始的指针, 填充数据,内存大小
char** ptr = &buffer;
delete[] buffer;
buffer=NULL;
delete ptr;
ptr=NULL; - 指针传参改变函数里的值
1
2
3
4
5
6
7
8
9
10void Increment(int* value)
{
(*value)++; //先逆指针操作该地址的值,自加一
}
int main()
{
int a=5;
Increment(&a);
std::cout << a << std::endl;//a的值为6
}
引用
- 引用必须引用已经存在的变量,并不占用内存
1
2
3
4
5int a=5;
int& ref = a;//给a创建别名为ref
ref = 2;//通过ref改变a的值
std::cout << a << std::endl;//a的值为2 - 引用传参数
1
2
3
4
5
6
7
8
9
10void Increment(int& value)
{
value++; //先逆指针操作该地址的值,自加一
}
int main()
{
int a=5;
Increment(a);
std::cout << a << std::endl;//a的值为6
}
c++类
- 类是将变量分组到一个类型中,并为这些变量添加功能
- 类中的私有变量只有类中的函数才能访问
- 类内的函数称为方法—改变对象的值的函数
- 类与结构体的区别是结构体相当于都是公有变量和函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Player
{
public:
int x,y;
int speed;
void Move(int xa,int ya)
{
player.x += xa*player.speed;
player.y += ya*player.speed;
}
};
Player player;//实例化一个对象
player.x = 5;
player.Move(1,-1);
静态static
- static代表仅在该翻译单元—cpp文件中使用,别的cpp无法寻找到
1
static int speed=5;
- 若要使用别的cpp中的变量或者函数,需要本文件加上extern//static变量仍然无法被找到
1
extern int speed
- 没有加static的全局变量,编译器会跨翻译单元寻找,即1.cpp中可以使用2.cpp定义的变量,如果1.cpp定义了相同变量则会出错
- 类和结构体中的静态static—数据不会再类实例之间变化(一块内存)可以用来共享数据;静态方法不能访问非静态变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24struct Entity
{
static int x,y;
void Print()
{
std::cout << x << "," << y << std::endl;
}
};
int Entity::x;//必须定义静态变量
int Entity::y;
Entity e;
e.x =2;
e.y =3;
Entity e1;
e1.x =5;
e2.y =8;
e.Print();
e1.Print();
std::cin.get();
//输出为
//5,8
//5,8
枚举
- 枚举实例化后只能是其中的一个数,枚举中的内容分别存放的数据为0,1,2…..//默认,也可以自己赋值但是只能整数
1
2
3
4
5
6
7
8
9enum Example
{
A,B,C
};
Example value =B;
if(value ==1)
{
std::cout << value << std::endl;//value的值为1
}
构造函数
- 构造函数目的是在实例化对象时作的初始化工作,包括变量的初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Entity
{
public:
float X,Y;
Entity()
{
X=0.0f;
Y=0.0f;
}
};
Entity e;
std::cout << e.X << "," << e.Y << std::endl;
//输出为0,0
析构函数
- 一个实例化对象在销毁时,析构函数会自动调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Entity
{
public:
float X,Y;
Entity()
{
X=0.0f;
Y=0.0f;
}
~Entity()
{
std::cout << "对象已经消除" << std::endl;
}
};
Entity e;
std::cout << e.X << "," << e.Y << std::endl;
//输出为0,0
继承
- 子类将具有父类所有变量和函数,同时增加了新的变量或函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Entity
{
public:
float X,Y;
void Move(float xa,float ya)
{
X +=xa;
Y +=ya;
}
};
class Player : public Entity
{
const char* Name;
void PrintName()
{
std::cout << Name << std::endl;
}
};
Player player;
player.Move(5,5);
player.X=2;
虚函数
- 虚函数目的是指为子类重写来自继承父类的函数,让它做其他事,父类的函数要加上virtual
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Entity
{
public:
virtual std::string GetName()
{
return "Entity";
}
};
class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name){}//:的作用是初始化变量m_Name的值为name传入的值
std::string GetName()
{
return m_Name;
}
};
Entity* e = new Entity();
std::cout << e->GetName() << std::endl;
Player*p =new player("Cherno");
std::cout << p->GetName() << std::endl;
//输出为 Entity Cherno
纯虚函数
- 纯虚函数允许在基类中定义一个没有实现的函数,强制子类去实现该函数(接口)
1
2
3
4
5class Entity
{
public:
virtual std::string GetName()=0;//此时为纯虚函数
};
可见性
- private 只有该类以及友元可见,子类不可见
- protect 只有该类,友元,子类可见
- public 均可见
数组
- 数组名就是指针类型
1
2
3
4
5
6
7
8
9
10int example[5];
example[0]=2;
example[4]=4;
//打印某个索引对应的值
std::cout << example[0] << std::endl;
//打印整个数组的值只需要打印这个数组的地址--数组名就是指针类型
std::cout << example << std::endl;
for (int i=0; i<5;i++)
example[i]=2;
std::cin.get(); - 指针控制数组
1
2
3
4
5int example[5];
int* ptr = example;
example[2]=4;//改变example[4]的值为4
*(ptr + 2)=6;//改变example[4]的值为6 - new创建数组—直接创建的是在栈上,生存在函数里,new是在堆上,销毁前一直存在
1
2
3int example[5];//创建数组名为example的数组
int* another=new int[5];//创建数组名为another的数组
delete[] another;
字符串
- 字符串数组最后一位默认为0,遇到0才知道数组数据到哪停止
- 字符串数组单个放值时,自己加上隐藏位0
1
2
3
4
5
6char* name ="Cherno";//字符串数组
name[2] ='a';//name数组此时为Charno
std::cout << name << std::endl;//name数组此时为Charno
char* name2[7] ={'C','h','e','r','n','o',0};//字符串数组
std::cout << name2 << std::endl;//name2数组此时为Charno - 使用std::string ,默认是const char*类型
1
2
3
4
std::string name ="Cherno";//字符串数组
std::cout << name << std::endl;//name数组此时为Charno - 字符串操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::string name ="Cherno";//字符串数组
//字符串长度
strlen(name);
//复制字符串
strcpy(name);
//追加字符串
name =std::string("Cherno")+"hello";
std::cout << name << std::endl;//name数组此时为Charnohello
//查找字符串--返回的是查找字符串的首位置
name.find("no")//在name数组字符串中查找no
//查找是否存在某字符串
bool contains=name.find("no")!=std::string::npos;
const--常量
- 不可修改,只读
1
2
3
4
5
6
7const int a=5;
a=2;//提示错误,不可更改
const std::string& GetName() const//该函数不允许修改值
{
return m_Name;
}
//该函数返回一个不允许修改的常量
构造函数初始化列表
- 构造函数执行时初始化类成员(变量)方法一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Entity
{
private:
std::string m_Name;
public:
//默认构造函数
Entity()
{
m_Name="Unknow";
}
//接受name作为参数的构造函数
Entity(const std::string& name)
{
m_Name=name;
}
const std::string& GetName() const//该函数不允许修改值
{
return m_Name;
}
};
Entity e("Cherno");
std::cout << e.GetName() << std::endl;
//输出为Cherno - 方法二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Entity
{
private:
std::string m_Name;
int m_Score;
public:
//初始化类成员m_Name为Unknow,m_Score为0
Entity()
:m_Name("Unknow"),m_Score(0);
{
}
const std::string& GetName() const//该函数不允许修改值
{
return m_Name;
}
};
Entity e;
std::cout << e.GetName() << std::endl;
//输出为Unknow
三元操作符
- 和简单的if可等价但是操作更快
1
2
3
4
5
6
7if (a>5)
b=0;
else
b=1;
//三元操作符
b=a>5?0:1;//a大于5则b取0,否则b取1
std::string rank = a>10? "Master":"Beginner";//a大于5则rank取Master,否则rank取Beginner
初始化对象
- 栈里初始化,离开作用域会被释放//栈很小1-2M
1
2
3
4
5
6
7
8class Entity
{
private:
public:
};
Entity e; - 堆里初始化,程序员下发释放内存指令前一直都在//花费时间长
1
2
3
4
5
6
7
8
9
10
11class Entity
{
private:
public:
};
Entity* e=new Entity;
delete e;//删除指针
new
1 | int* b=new int[50];//200 bytes,b为数字长度50 |
this
- this是指向当前对象实例的指针,this->访问对象里的数据,*this就是对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17void PrintEntity(const Entity& e)//参数是一个Entity类的对象,e是别名
class Entity
{
private:
public:
int x,y
Entity(int x,int y)
{
this->x=x;//把传入的变量x的值给该对象的成员变量x
this->y=y;//把传入的变量y的值给该对象的成员变量y
PrintEntity(*this)//把这个对象传给函数
}
};
智能指针
- 使用智能指针unique_ptr(优先使用),超出作用域{}会自动销毁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Entity
{
private:
public:
Entity()
{
std::cout << "创建成功" << std::endl;
}
~Entity()
{
std::cout << "销毁成功" << std::endl;
}
void Print(){}
};
{ //创建一个Entity类的对象e
std::unique_ptr<Entity> e=std::make_unique<Entity>()
e->Print();
//此时输出创建成功
}
//此时输出销毁成功 - 使用智能指针shared_ptr将对象传递到另一个函数中或类中,相当于对象的接替者,引用计数,计数为0则删除指针,内存释放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Entity
{
private:
public:
Entity()
{
std::cout << "创建成功" << std::endl;
}
~Entity()
{
std::cout << "销毁成功" << std::endl;
}
void Print(){}
};
{ ////创建Entity类实例化对象e0的智能指针
std::shared_ptr<Entity> e0;
{
//创建Entity类实例化对象e的智能指针
std::shared_ptr<Entity> e=std::make_shared<Entity>();
//此时输出创建成功
e0=e;//复制指针e0指向该对象,即使e死了e0仍然代替e使用
}
//e对象死了
}
//e0死了 该对象彻底玩了,此时输出销毁成功