c++学习笔记

个人学习笔记,仅供参考,如有错误,欢迎指正。

目录

目录

c++面向对象

c++的输入输出:

引用

c++中的静态(static)

 构造函数

析构函数

继承

虚函数

可见性

数组和字符串

const

mutable

成员初始化

三元运算符

new

隐式转换与explicit

重载

this

智能指针

 复制与拷贝构造函数

箭头->操作符

c++ vector 动态数组

模板

堆与栈的内存

宏定义

 auto关键字

静态数组array

函数指针

lambda

namepace

线程

计时

多维数组

排序

类型双关

共用体union

虚析构函数

c++的类型转换

预编译头文件

dynamic_cast

基准测试

结构化绑定

optional

单一变量存放多种类型的数据



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();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值