个人学习笔记,仅供参考,如有错误,欢迎指正。
目录
目录
c++面向对象
比如你想吃饭,面向过程就是你要亲历亲为,自己去做,洗菜炒菜啊什么的
而面向对象就是,你可以点外卖,让别人帮你买啊什么的
c++的输入输出:
#include<iostream>
//using namespace std;//使用命名空间
//有上面这个下面的变量就可以不用换加std::没有就要加
int main()
{
int a;
std::cin >> a;//输入
std::cout <<a <<std:: endl;//输出 endl是换行的意思,去掉<<和endl就是不换行
std::cin.get();
}
//连续输入两个数字 cin>>a>>b;
//连续输出两个数字 cout<<"a="<<a<<endl;
static可以让一个函数/变量只在局部使用,可以使这个函数/变量只声明在这个翻译单元中,编译器把我们给他的文件变成翻译单元。翻译单元又会生成一个obj文件。编译——链接。
continue只跳出当前轮次的循环,比如循环五次,遇到一个continue会不执行continue下面的程序直接进入下一轮循环。
break是完全跳出当前所在的for循环。如果有三个相嵌套的for循环,break在最里面那层,break会跳到第二层for循环那里。
可以设置断点逐步执行来看到具体的过程。
for (int i = 0;i < 5;i++)
{
//continue;//如果在前面代码会一直跳出循环不会打印出东西
//if(i>2)
//break;如果是break就完全跳出不会继续执行后面的循环
cout << "hello word !" << endl;
continue;//在后面会打印后再跳出循环
}
指针是保存内存地址的整数,Null空指针指代0,而nullptr是专门用来代表空指针传参为指针而不是0(Null)。
引用
int a = 8;
int& c = a;//相当于给a取了个别名,并不是创建了一个新变量
//当声明一个引用时需要给他赋值,必须要引用一些东西。
c = 6;
cout << a << endl;//这样打印出来的是6
在另一个函数改变值,可以传变量的地址,或使用引用&(c++)
void add(int& a)//要用指针改变值应该是(int *a)
{
a++;//要使用指针应该是(*a)++;
}
int main()
{
int a = 5;
//add(a);//直接传输过去不会改变a的值
add(a);//可以传过去a的地址,进而改变a的值,要使用指针传递应该是(&a);
cout << a << endl;
std::cin.get();
}
类
类有六个默认成员函数:构造函数,析构函数,拷贝构造函数,赋值重载,取地址重载。
面向对象编程,没有类一些功能也能完成,但是类可以让我们的代码变得简洁,更加方便维护
class Player
{
public: //这意味这我们可以在类之外的任何地方访问这些变量
//private可以设置为只在内部使用
int x, y;
int speed;
void Move(int xa, int ya)//可以在里面放函数
{
x += xa * speed;//所有的x,y都是指的类里面的
y += ya * speed;
}
};
int main()
{
Player player;
player.Move(1, -1);
std::cin.get();
}
c++中的静态(static)
类和结构体外部的静态
修饰全局变量让改变量只能在当前文件中使用,只能在当前翻译单元可用。
static int a;//意思是只能在翻译单元内部连接
extern int a;//在外部翻译单元寻找变量a
类和结构体内部
在哪里使用:共享数据的时候,一个变量可以在全局更改
class Text
{
public:
static int x, y;
void print()//加上static这个函数就不知道打印的x,y是什么东西了,
//就要传参过去才能打印而x也要变为text.x.......
{
cout << x << "," << y << endl;
}
};
int Text::x;
int Text::y;
int main()
{
Text text;
text.x = 5;
text.y = 6;
Text tex;//当我们改变这个时实际上改变的和第一个完全一样
tex.x = 0;//他们指向的是相同的内存
tex.y = 1;
text.print();
tex.print();//两个打印出来的都是0 1 0 1
}
局部变量
修饰局部变量会延长相应的生命周期
void function()
{
static int i = 0;//加上static时打印出来的结果是1234
i++;
cout << i << endl;
}
int main()
{
function();
function();
function();
function();
}
构造函数
构建函数的名字与类名相同,保证每一个数据成员都有一个合适的初始值,
主要任务就是初始化成员,
class Enity
{
public:
int x, y;
//Enity(){}如果没有定义构造函数,这就是编译器默认生成的构造函数
Enity(int X ,int Y)//这里也可以写入参数,带参数传
{
x = X;
y = Y;
}
void print()
{
std::cout << x << "," << y << std::endl;
}
};
int main()
{
Enity e(8,9);//要带参数必须加(参数),不带不加()
e.print();
std::cin.get();
}
析构函数
对象生命周期结束时,c++编译器系统自动调用析构函数
class Enity
{
public:
Enity(){
std::cout << "调用构造函数" << std::endl;
}
~Enity()//这就是析构函数
{
std::cout << "调用析构函数" << std::endl;
}
};
void function()
{
Enity x;
}
int main()
{
function();
std::cin.get();
}
继承
class Entity
{
public:
float X, Y;
void Move(float xa, float ya)
{
X += xa;
Y += ya;
}
};
class Player :public Entity//继承了Entity中public的一部分
//可以使用Entity中的变量,函数
{
public:
const char* Name;
float X, Y;
};
虚函数
#include<iostream>
#include<string.h>
class Entity
{
public:
virtual std::string GetName() { return "Entity"; }//virtual为这个函数生成v表 他被重写了
};//如果GetName=0;就意味着它是一个纯虚函数,必须在一个子类中实现
class Player :public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
:m_Name(name) {}
std::string GetName()override { return m_Name; }//c++11里面的 表明这是一个复写的函数 增加了函数的可读性
};
void PrintName(Entity* entity)//不用虚函数调用的是Entity里面的函数,就会打印两个Entity
{
std::cout << entity->GetName() << std::endl;
}
int main()
{
Entity* e = new Entity();
PrintName(e);
Player* p = new Player("Cherno");
PrintName(p);
std::cin.get();
}
c++接口纯虚函数
只有实现了所有纯虚函数之后才能实例化
#include<iostream>
#include<string.h>
class Printable
{
public:
virtual std::string GetClassName() = 0;//纯虚函数
};
class Entity:public Printable
{
public:
std::string GetClassName() override{ return "Entity"; }
};
class Player :public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
:m_Name(name) {}
std::string GetClassName() override { return "Player"; }
};
void Print(Printable* obj)
{
std::cout << obj->GetClassName() << std::endl;
}
int main()
{
Entity* e = new Entity();
Player* p = new Player("Cherno");
Print(e);
Print(p);
std::cin.get();
}
可见性
#include<iostream>
class Entity
{
//private://只有这个类里面的可以访问
protected://意味着继承这个类的也可以访问 main函数不可以
public://所有都可以访问 mian函数也可以
int X, Y;
void print(){}
public:
Entity()
{
X = 0;
print();
}
};
class Player :public Entity
{
public:
Player()
{
int X = 2;
print();
}
};
int main()
{
Entity e;
e.print();
e.X = 2;
std::cin.get();
}
数组和字符串
#include<iostream>
int main()
{
char name[4] = { 'a','b','c','d' };
const char* name1 = "abcd";
std::cout << name << std::endl;//这里会出现乱码,因为没有加\0
std::cout << name1 << std::endl;
std::cin.get();
}
/*
#include<iostream>
#include<string>//注意一下string这个头文件
int main()
{
int a = 0;
std::string name1 = "hello";
a = name1.size();
//a=name1.size();//不包括\0,只计算\0之前的
//如果是c语言就要用strlen();
std::cout << a<< std::endl;
std::cin.get();
}
*/
const
#include<iostream>
int main()
{
const int age = 90;
//const int* a = new int;//这样定义不能改变a所指向的内容
//但是可以让指针地址改变,指向的东西不能改变
int* const a = new int;
//这样不能改变指针地址,可以改变a指向的内容
*a = 2;
a = (int*)&age;
std::cout << *a << std::endl;
std::cin.get();
}
/*
#include<iostream>
class Entity
{
private:
int m_X, m_Y;
public:
int GetX() const//不能修改成员,只能读取
{//如果不需要修改最好加上const
//m_X = 2;//这样不行
return m_X;
}
int SetX(int x)
{
m_X = x;
}
};
*/
mutable
class player {
private:
int x;//mutable int x;
public:
void print() const
{
x++;//不可以修改
//但如果int x 改为int mutable n那就可以修改
std::cout << "hello" << std::endl;
}
};
成员初始化
#include<iostream>
class example
{
public:
example()
{
std::cout << "example1" << std::endl;
}
example(int x)
{
std::cout << "example2" << std::endl;
}
};
class Entity
{
public:
int x, y;
example e;
Entity()
//:e(example(5))//在这里初始化只会打印一个
{
//e = example(5);//这样会打印两个例子
//如果在这里的话 他会先用默认的 然后再用创建的
}
};
int main()
{
Entity a;
}
三元运算符
#include<iostream>
int main()
{
int x=10;
x=x > 6 ? 2 : 100;
std::cout <<x<< std::endl;
}
new
#include<iostream>
class Entity {
};
int mian()
{
int* a = new int[20];
Entity* e = new Entity();//这个调用了构造函数
Entity* e = (Entity*)malloc(sizeof(Entity));//这个没有调用构造函数
//相等
delete e;//必须手动delete
delete[] a;
}
隐式转换与explicit
#include<iostream>
#include<string>
class Entity {
private:
std::string m_Name;
int m_Age;
public:
Entity(const std::string& name)
:m_Name(name),m_Age(-1) {}
//如果在前面加上 explicit 下面就不能做隐式转化了
//只能是Entity a("cherno");这样
Entity(int age)
:m_Name("Unknow"),m_Age(age) {}
};
void PrintEntity(const Entity& entity)
{
//printing
}
int mian()
{
Entity a("cherno");
Entity b(22);
//Entity a="cherno";//可以这样写,它隐式的将22转化一个Entity,构造出一个Entity
//Entity b = 22;
PrintEntity(22);
PrintEntity("cherno");//这样不行 只能做一次隐式转化
//这里做了两次隐式转化 一个const char数组到string 一个string到Entity
//要改为PrintEntity(std::string("cherno"));
//或者PrintEntity(Entity("cherno"));
}
重载
#include<iostream>
#include<string>
struct Vector2
{
float x, y;
Vector2(float x, float y)
:x(x),y(y) {}
Vector2 Add(const Vector2& other) const
{
return Vector2(x + other.x, y + other.y);
}
Vector2 operator+(const Vector2& other) const
{
return Add(other);
}
Vector2 Multiply(const Vector2& other) const
{
return Vector2(x * other.x, y*other.y);
}
Vector2 operator*(const Vector2& other) const
{
return Multiply(other);
}
};
std::ostream& operator << (std::ostream & stream, const Vector2 & other)
{
stream << other.x << "," << other.y;
return stream;
}
int main()
{
Vector2 position(4.0f, 4.0f);
Vector2 speed(0.5f, 1.5f);
Vector2 powerup(1.1f, 1.1f);
Vector2 result = position.Add(speed.Multiply(powerup));
Vector2 result2 = position+speed*powerup;//重载后
std::cout << result2 << std::endl;//重载后 之前不可用
std::cin.get();
}
this
#include<iostream>
#include<string>
class Entity
{
public:
int x, y;
Entity(int x, int y)
{
this->x = x;//this是一个关键字指向当前对象
this->y = y;//只能在类的内部 是一个指针 值不能被修改
}
};
//不要试图delete这个this不然会嗝屁
int main()
{
std::cin.get();
}
智能指针
#include<iostream>
#include<memory>//智能指针
class Entity
{
public:
Entity()
{
std::cout << "created Entity" << std::endl;
}
~Entity()
{
std::cout << "destory Entity" << std::endl;
}
void print(){}
};
int main()
{
{
std::shared_ptr<Entity> e0;//这里如果换成弱指针 出了最里面那个大括号就会释放
{
//作用域指针
std::unique_ptr<Entity> entity(new Entity());//需要显示构造函数
//ptr不支持拷贝和赋值
//上面这个 推荐写成下面这样
std::unique_ptr<Entity> entity = std::make_unique<Entity>();
entity->print();//离开最近的一个大括号自动destory 避免了delete
//共享指针 可以复制
//引用计数 假如引用计数是2 创建一个共享指针 又有一个共享指针用来复制的
//如果第一个指针没了计时器就会减1 第二个也没了就释放内存 有eg
std::shared_ptr<Entity>sharedEntity = std::make_shared<Entity>();
e0 = sharedEntity;
//弱指针
std::weak_ptr<Entity>weakEntity = sharedEntity;
//这里不会增加计数
}
}//当是共享指针时出了左边这个大括号e0才会触发析构函数
}
复制与拷贝构造函数
#include<iostream>
#include<string>
class String
{
private:
char* m_Buffer;//String second = string; 如果在下面是这样会崩溃 因为试图两次delete
unsigned int m_Size;
public:
String(const char* string)
{
m_Size = strlen(string);
m_Buffer = new char[m_Size+1];
memcpy(m_Buffer, string, m_Size);//复制 目的 来源 尺寸
m_Buffer[m_Size] = 0;
}
String(const String& other)//c++默认提供的拷贝构造函数 深度拷贝
//如果让它等于delete 就相当于禁用了拷贝
:m_Size(other.m_Size)
{
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
}
~String()
{
delete[] m_Buffer;
}
char& operator[](unsigned int index)
{
return m_Buffer[index];
}
//不设置友元在下面这个函数内部无法访问私有成员
friend std::ostream& operator<<(std::ostream& stream, const String& string);
};
std::ostream& operator<<(std::ostream& stream, const String& string)
{
stream << string.m_Buffer;
return stream;
}
void PrintString(const String& string)
{
std::cout << string << std::endl;
}
int main()
{
String string = "cherno";
String second = string;
second[2] = 'a';
PrintString(string);
PrintString(second);
}
箭头->操作符
#include<iostream>
class Entity
{
public:
int x;
public:
void Print() const { std::cout << "hello" << std::endl; }
};
class ScopedPtr
{
private:
Entity* m_Obj;
public:
ScopedPtr(Entity* entity)
:m_Obj(entity)
{
}
~ScopedPtr()
{
delete m_Obj;
}
Entity* operator->()
{
return m_Obj;
}
const Entity* operator->() const
{
return m_Obj;
}
};
int main()
{
const ScopedPtr entity = new Entity();
entity->Print();
std::cin.get();
}
c++ vector 动态数组
#include<iostream>
#include<string>
#include<vector>//vector
/*
动态数组 可以根据需要改变数组大小
内存空间是连续的
*/
struct Vertex
{
float x, y, z;
};
//运算符重载
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex)
{
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
int main()
{
//std::vector<int>a(10);//创建a数组十个元素
//std::vector<int>a(10,6);//是个元素均为6
//a.back();//返回最后一个元素,front();返回第一个元素
//a.clear();//清空a中元素
std::vector<Vertex>vertices;
// 类型 name
//复制拷贝需要完全赋值 一片连续的空间
//而指针只需要赋值地址
vertices.push_back({ 1,2,3 });
//在容器的最后一个位置插入
vertices.push_back({ 4,5,6 });
for (int i = 0; i < vertices.size(); i++)
std::cout << vertices[i] << std::endl;
vertices.erase(vertices.begin() + 1);//删除第二组数据
for (Vertex& v:vertices)
//基于range的for循环
//加上&这里就是直接引用 没有复制
std::cout<< v << std::endl;
vertices.clear();//会将容器内容清空 size为0 但储存空间未变
std::cin.get();
}
vector使用优化
#include<iostream>
#include<vector>
struct Vertex
{
float x, y, z;
Vertex(float x, float y, float z)
:x(x), y(y), z(z)
{
}
Vertex(const Vertex& vertex)//c++提供的默认拷贝构造函数
:x(vertex.x),y(vertex.y),z(vertex.z)
{
std::cout << "copied!" << std::endl;
}
};
int main()
{
std::vector<Vertex>vertices;
//vertices.push_back(Vertex(1, 2, 3));//打印1次
//1 把main()创建的vertex复制到vector
//vertices.push_back(Vertex(4, 5, 6));//打印3次(包括第一次)
//2 与1相同
//3 vector容量增加复制了一份
//vertices.push_back(Vertex(7, 8, 9));//打印6次
//4与1相同
//5 6 容量是2 复制了两个vector
//上面运行打印了6次copied
vertices.reserve(3);//不用增加容量了 -3
vertices.emplace_back(1, 2, 3);
vertices.emplace_back(4, 5, 6);
vertices.emplace_back(7, 8, 9);
//传递构造函数的参数列表
//在vector中 使用这些参数构造一个vertex的对象
//实在vector中 不用复制-3 拷贝复制次数变为了0次
std::cin.get();
}
使用库 静态/动态连接
静态连接是在编译时发生的,当你编译一个静态库的时候,将其连接到可执行文件,也就是应用程序,动态连接发生在运行时,
模板
#include<iostream>
#include<string>
//模板
template<typename T>
//当我们调用时 基于传递的参数 创建函数
void Print(T value)
{
std::cout << value << std::endl;
}
int main()
{
Print(5);
// Print<int>(6);
Print("hello");
Print(5.5f);
std::cin.get();
}
#include<iostream>
#include<string>
template<typename T,int N>
class Array
{
private:
T m_Array[N];
public:
int GetSize() const { return N; }
};
int main()
{
Array<int,5> array;//把N换成5构造类
//这里时以int 和5 创建了一个类,替代了类中的T 和N
std::cout << array.GetSize() << std::endl;
std::cin.get();
}
堆与栈的内存
#include<iostream>
#include<string>
struct Vector3
{
float x, y, z;
};
int main()
{
int value = 5;//在栈上分配整数
int array[5];
Vector3 vector;
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;
//连续的
int* hvalue = new int;//在堆上分配
*hvalue = 5;
int* harray = new int[5];
Vector3* hvector = new Vector3();
harray[0] = 1;
harray[1] = 2;
harray[2] = 3;
harray[3] = 4;
harray[4] = 5;
//不连续
}
宏定义
#include<iostream>
#include<string>
#if 0
#define LOG(x) std::cout<<x<<std::endl;
#endif
int main()
{
LOG("hello");
std::cin.get();
}
auto关键字
#include<iostream>
int main()
{
auto a = 5;//根据后面的内容选择类型
//改变函数返回类型而不改变调用函数的变量可以使用
//长类型
}
静态数组array
#include<iostream>
#include<array>
//array<类型名,元素个数>
//使用时要初始化
int main()
{
std::array<int, 5> a;
a.size();//返回数组大小
a.back() = 9;//返回最后一个元素的引用,改变最后一个元素值
a.front() = 6;//返回第一个元素的引用,改变第一个
a.data();//返回第一个元素的指针
std::cout << *(a.data()+4)<< std::endl;
std::cin.get();
}
函数指针
#include<iostream>
void HelloWord()
{
std::cout << "hello word" << std::endl;
}
int main()
{
auto function = HelloWord;//相当于&HelloWord
//相当于
//void(*function)() = HelloWord;
function();
std::cin.get();
}
#include<iostream>
#include<vector>
void PrintValue(int value)
{
std::cout << "value :" << value << std::endl;
}
void ForEach(const std::vector<int>& values,void(*func)(int))
{
for (int value : values)
func(value);
}
int main()
{
std::vector<int> values = { 1,5,4,2,3 };
ForEach(values, PrintValue);
std::cin.get();
}
lambda
lambad是我们不需要通过函数的定义就可以定义一个函数的方法,
#include<iostream>
#include<vector>
void PrintValue(int value)
{
std::cout << "value :" << value << std::endl;
}
void ForEach(const std::vector<int>& values,void(*func)(int))
{
for (int value : values)
func(value);
}
int main()
{
std::vector<int> values = { 1,5,4,2,3 };
//ForEach(values, PrintValue);
ForEach(values, [](int value) { std::cout << "Values: " <<value<< std::endl; });
std::cin.get();
}
#include<iostream>
#include<vector>
#include<functional>//function
#include<algorithm>//find_if
void ForEach(const std::vector<int>& values,const std::function<void(int)>& func)
{
for (int value : values)
func(value);
}
int main()
{
std::vector<int> values = { 1,5,4,2,3 };
auto it=std::find_if(values.begin(), values.end(), [](int value) {return value > 3; });
//begin第一个元素指针 end最后一个元素指针
std::cout << *it << std::endl;
int a = 5;
auto lambda = [=](int value) { std::cout << "Values: " << a << std::endl; };
// [=]传递所有变量通过值传递 [&]传递所有变量通过引用传递
// []mutable(){};以改变其值
ForEach(values, lambda);
std::cin.get();
}
namepace
#include<iostream>
#include<string>
#include<algorithm>//reverse
namespace apple {
void print(const char* text)
{
std::cout << text << std::endl;
}
}
namespace orange {
void print(const char* text)
{
std::string temp = text;
std::reverse(temp.begin(), temp.end());
std::cout << temp << std::endl;
}
}
int main()
{
//尽量在使用的地方声明命名空间 不要滥用
using namespace orange;
namespace a = orange;
using apple::print;//只引用里面的print
a::print("hello");
std::cin.get();
}
线程
#include<iostream>
#include<thread>//线程
static bool s_Finished = false;
void DoWork()
{
using namespace std::literals::chrono_literals;//sleep_for();
std::cout << "Started id=" << std::this_thread::get_id() << std::endl;
while (!s_Finished)
{
std::cout << "Working...\n";
std::this_thread::sleep_for(1s);
}
}
int main()
{
std::thread worker(DoWork);
//如果不用线程他会一直在循环
std::cin.get();
s_Finished = true;
worker.join();
std::cout << "Finished" << std::endl;
std::cout << "Started id=" << std::this_thread::get_id() << std::endl;
std::cin.get();
}
计时
#include<iostream>
#include<chrono>//计时
#include<thread>//线程
struct Timer
{
std::chrono::time_point<std::chrono::steady_clock>start, end;//下面的auto的实际类型给写出来了
std::chrono::duration<float>duration;
Timer()
{
start = std::chrono::high_resolution_clock::now();
}
~Timer()
{
end=std::chrono::high_resolution_clock::now();
duration = end - start;
float ms = duration.count() * 1000.0f;
std::cout << "Timer took" << ms << "ms" << std::endl;
}
};
void function()
{
Timer timer;
for(int i=0;i<100;i++)
{
std::cout << "hello" << std::endl;
}
}
int main()
{
using namespace std::literals::chrono_literals;//sleep中的s
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(1s);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> duration = end - start;
std::cout << duration.count() << "s" << std::endl;
function();
std::cin.get();
}
多维数组
#include<iostream>
int main()
{
int** a2d = new int* [5];
for (int i = 0; i < 5; i++)
a2d[i] = new int[5];
//设置为2
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
a2d[x][y] = 2;
}
}
/*删除要遍历删除
for (int i = 0; i < 50; i++)
{
delete[] a2d[i];
}
delete[] a2d;
*///上面那种方式 随机分配内存 不是连续的内存块 读取要来回跳
int* array = new int[ 5 * 5 ];
//for (int i = 0; i < 5 * 5; i++)
//{
// array[i]=2;
//}
//或者是这样
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
array[x + y * 5] = 2;
//y每增加1就向前跳五个
}
}
/*
int*** a3d = new int** [50];
for (int i = 0; i < 50; i++)
{
a3d[i] = new int* [50];
for (int j = 0; j < 50; j++)
{
int** ptr = a3d[i];
ptr[j] = new int[50];
//a3d[i][j]=new int[50];与这样写一样 }
}
*/
}
排序
#include<iostream>
int main()
{
int** a2d = new int* [5];
for (int i = 0; i < 5; i++)
a2d[i] = new int[5];
//设置为2
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
a2d[x][y] = 2;
}
}
/*删除要遍历删除
for (int i = 0; i < 50; i++)
{
delete[] a2d[i];
}
delete[] a2d;
*///上面那种方式 随机分配内存 不是连续的内存块 读取要来回跳
int* array = new int[ 5 * 5 ];
//for (int i = 0; i < 5 * 5; i++)
//{
// array[i]=2;
//}
//或者是这样
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
array[x + y * 5] = 2;
//y每增加1就向前跳五个
}
}
/*
int*** a3d = new int** [50];
for (int i = 0; i < 50; i++)
{
a3d[i] = new int* [50];
for (int j = 0; j < 50; j++)
{
int** ptr = a3d[i];
ptr[j] = new int[50];
//a3d[i][j]=new int[50];与这样写一样 }
}
*/
}
类型双关
#include<iostream>
struct Entity
{
int x, y;
};
int main()
{
Entity e = { 5,8 };
//当我拥有的这段内存 当作不同类型的内存来对待
int* position = (int*)&e;
//这个e包含了int数组的开始地址 也就是包含了指向int的指针
int y = *(int*)((char*)&e + 4);//这得到了y的值
std::cout << position[0] << "," << position[1] << std::endl;
std::cin.get();
}
共用体union
#include<iostream>
union text
{
char a;
int b;
}t;
int main()
{
t.a = 'a';
std::cout << t.a << " " << t.b << std::endl;
//打印出a 97
int s = sizeof(text);
std::cout << s << std::endl;//打印出4
std::cin.get();
}
#include<iostream>
struct Vector2
{
float x, y;
};
struct Vector4
{
union//共用体
{
struct
{
float x, y, z, w;
};
struct
{
Vector2 a, b;
};
};
};
void PrintVector2(const Vector2& vector)
{
std::cout << vector.x << "," << vector.y << std::endl;
}
int main()
{
Vector4 vector = { 1.0f,2.0f,3.0f,4.0f };
PrintVector2(vector.a);
PrintVector2(vector.b);
vector.z = 500.f;
std::cout << "---------------" << std::endl;
PrintVector2(vector.a);
PrintVector2(vector.b);
std::cin.get();
}
虚析构函数
#include<iostream>
class Base
{
public:
Base() { std::cout<<"Base constructor\n"; }
~Base() { std::cout << "Base Dedtruvtor\n"; }
//如果允许它有子类一点要加virtual 虚构析函数
// 加上了才会与第二个打印结果相同
// 不然容易造成内存泄漏
//virtual ~Base() { std::cout << "Base Dedtruvtor\n"; }
};
class Derived:public Base
{
public:
Derived() { std::cout << "Derived constructor\n"; }
~Derived() { std::cout << "Derived Dedtruvtor\n"; }
};
int main()
{
Base* base = new Base();
delete base;
std::cout << "--------" << std::endl;
Derived* derived = new Derived();
delete derived;
std::cout << "--------" << std::endl;
Base* poly = new Derived();
delete poly;
std::cin.get();
}
c++的类型转换
const_cast
static_cast
dynamic_cast
reinterpret_cast
预编译头文件
#pragma once
#include<iostream>
#include<vector>
#include<memory>
//预编译头文件 可以包含一些常用几乎不会修改的库
//
// 加速编译过程 预编译头文件pch 让这些
// 文件预先编译成一个二进制文件 然后在编译其他
// 源文件时可以快速加载 避免了不必要的工作
//
//
//
//1创建头文件pch.h
//把项目设置为使用预编译头
//c/c++/预编译头/使用/并在下面预编译头文件添加pch.h
//源文件包含创建的头文件#include"pch.h"
//在源文件属性里把预编译头改为创建 并在下一行预编译头文件里面添加pch.h
dynamic_cast
虚基类到派生类的转化
派生类的指针赋值给基类的指针√
//c++的dynamic_cast
//它做了额外的工作来确保,我们实际的类型转换是有效的类型转换
class Entity
{
public:
virtual void PrintName() {}//多态 dynamic_cast必须包含多态
};
class Player :public Entity
{
};
class Enemy :public Entity
{
};
int main()
{
Player* player = new Player;
Entity* actuallyEnemy = new Enemy;
Entity* actuallyPlayer = player;
Player* p0 = dynamic_cast<Player*>(actuallyEnemy);//返回null
if (p0)
{
}
Player* p1 = dynamic_cast<Player*>(actuallyPlayer);//返回的有地址
}
基准测试
#include<iostream>
#include<memory>
#include<chrono>//timer
class Timer
{
public:
Timer()
{
m_StartTimepoint=std::chrono::high_resolution_clock::now();//开始计时
}
~Timer()
{
Stop();
}
void Stop()
{
auto endTimepoint = std::chrono::high_resolution_clock::now();
auto start = std::chrono::time_point_cast<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count();
auto end = std::chrono::time_point_cast<std::chrono::microseconds>(endTimepoint).time_since_epoch().count();
auto duration = end - start;
double ms = duration * 0.001;
std::cout<<duration << "us(" << ms << "ms)\n";
}
private:
std::chrono::time_point<std::chrono::high_resolution_clock>m_StartTimepoint;
};
int main()
{
int value = 0;
{
Timer timer;
for (int i = 0; i < 1000000; i++)
{
//在release下是0 直接得出结果 不需要计时
//你要确保你确实做了这些事情
value += 2;
}
}
std::cout << value << std::endl;
}
结构化绑定
#include<iostream>
#include<string>
#include<tuple>
std::tuple<std::string, int>CreatePerson()
{
return { "cherno",24 };
}
int main()
{
/*
auto person = CreatePerson();
//auto = std::tuple<std::string, int>
std::string& name = std::get<0>(person);//返回第一个参数
int age = std::get<1>(person);//返回第二个参数
*/
/*
//更倾向于用下面这种 像一个容器
std::string name;
int age;
std::tie(name, age) = CreatePerson();
*/
//but c++17提供了新的特性 结构化绑定
//确保我们的语言标准是c++17
auto [name, age] = CreatePerson();;
// 我们给变量的两个名字
std::cout << name;
// 可以改变其值
//tuple支持更多的类型 所以不用pair
/*一个函数中返回多值 可以用指针 结构体 */
}
optional
#include<iostream>
#include<fstream>//文件读取
#include<string>
#include<optional>
//opptional c++11
std::optional<std::string> ReadFileAsString(const std::string& filepath)
{
std::ifstream stream (filepath);
if (stream)
{
std::string result;
// read file
return result;
}
return {};
}
int main()
{
std::optional<std::string>data = ReadFileAsString("data.txt");
std::string value = data.value_or("Not present");//如果不存在 返回我们传入的值
std::cout << value << std::endl;
//可以用来基准测试 传一个数
std::optional<int> count;
int c = count.value_or(100);
if (data.has_value())//可以是data
{
std::cout << "File read successfuly!\n";
}
else
{
std::cout << "File could not be opened!\n";
}
std::cin.get();
}
单一变量存放多种类型的数据
#include<iostream>
#include<variant>
//单一变量存放多种类型的数据 c++17
struct a{
int n;
std::string m;
};
int main()
{
std::variant<std::string, int>data;
std::cout << sizeof(int) << "\n";
std::cout << sizeof(std::string) << "\n";
std::cout << sizeof(data) << "\n";
//ta创建了一个结构体
a A;
std::cout << sizeof(A) << "\n";
std::cin.get();
}