c++ 学习笔记

学习笔记 更新ing

前言:这篇文章是Cherno教学视频的笔记,看了这个系列的C++教程后,很多之前看代码时看不懂的和调试代码时解决不了的bug都豁然开朗,膜拜大佬啊

vistual studio

修改输出目录与中间目录:

c++ 学习笔记_第1张图片

添加插件:vsvim

c++ 学习笔记_第2张图片

链接器(linker) P07

unsolved external symbol

POD: plain old data

calling convention :函数调用约定     calling convention_安静平和的博客-CSDN博客

   VC的编译环境默认是使用_cdecl调用约定,也可以在编译环境的Project Setting...菜单 -> C/C++ -> Code  Generation项选择设置函数调用约定。也可以直接在函数声明前添加关键字__stdcall、__cdecl或__fastcall等单独确定函数的调用方式。在Windows系统上开发软件常用到WINAPI宏,它可以根据编译设置翻译成适当的函数调用约定,在WIN32中,它被定义为_stdcall。  

class中一些调用约定(calling convention)

  • m_ 前缀: 表示该类成员变量 (class member variable)是 该类私有的
  • s_前缀: 表示该变量是 static的

Variable P08

当我们看一个变量时要看两点:1、生命周期  2、作用域

Reference P17

reference 作为函数返回值, const int& function()  返回的reference 不能是函数内的临时变量。因为临时变量在函数结束后就会消失,因此返回的引用无效

static  P21 P22 P23

outside class/struct :

  • static 声明的变量或者函数只能被当前的translation unit(也可以说是.cpp文件)发现,相当于类内的private ,
  • 如果外部文件想调用该static变量 需要 在外部文件当中使用extern 声明

 inside class/struct  :

  • 类内静态变量已经不属于类内变量,可以在没有实例化的情况下直接使用class::static variable的方式进行调用
  • 需要注意的是在使用这种方法进行调用static variable时需要先声明(declare)一下静态成员变量 type  class::static variable(it like we made two variables( the static variables in class ) that are inside a namespace called Entity ( the class name ) ),
  • 类内静态函数无法操作类内非静态变量( static methods cannot access non static variable  the reason is that a static method does not have a instance ),
  • 类内静态变量在所有实例(instance)中公用统一内存地址(share the same address),
  • 静态成员变量(类内静态变量)不能在构造函数中初始化
class Entity
{
public:
	static int x, y;
	static void Print()
	{
		std::cout << x << "," << y << std::endl;
	}
};
int Entity::x;
int Entity::y;
int main()
{
	Entity::x = 1;
	Entity::y = 2;
	Entity::Print();
	Entity::Print();
}

Singleton class单例类:

实现方式1

class Singleton
{
private:
	static Singleton* s_Instance;
public:
	static Singleton& Get() { return *s_Instance; }
	void Hello() { std::cout << "Hello Singleton!" << std::endl; }
};
Singleton* Singleton::s_Instance = nullptr;
//the Singleton::s_Instance cannot be declared in the main scope, I do not know why
int main()
{
	Singleton::Get().Hello();
}        

实现方式2:

class SingletonStatic
{
public:
	static SingletonStatic& Get()
	{
		static SingletonStatic* s_Instance;
		return *s_Instance;
	}
	void Hello(){LOG("Hello SingletonStatic!") }
};
int main()
{
	SingletonStatic::Get().Hello();
}

程序运行结果: 

Hello SingletonStatic!
Hello Singleton!
1,2
1,2
[WARNING]: Hello!

Constructors P25

  • c++的类会有默认的隐式构造函数,可以不写构造函数
  • 将构造函数设置成私有(private),那么该类不能实例化(instantiate) 只能通过 class::method()的方式调用成员函数
  • 可以通过default constructor()=delete;删除构造函数实现上一条

Destructors  P26

Inheritance  P27

(Polymorphism)

Virtual Function P28

  • Virtual Function introducing something that called Dynamic Dispatch witch compile is typically implemented by Vtable(Virtual Function Table)
  • 虚函数表 参考:C/C++杂记:虚函数的实现的基本原理​​​​​​​
  • 关于Dynamic Dispatch参考:方法调用的编译和运行:static dispatch和dynamic dispatch_慕课手记
  • 用于继承中的多态(Polymorphism)与覆盖(override)重载(Overload)   
  • 如果基类中的GetName函数不是virtual的,那么main函数中的entitya->GetName()输出的就是EntityA ,而不是Cherno
  • Player类中的GetName()函数的关键子override可写可不写,不影响结果,写了override后IDE会检查覆盖函数名  是不是与基类中相同 .关于override overload 与 overwrite参考:C++中overload,override,overwrite的区别详细解析_线上幽灵-CSDN博客
class EntityA
{
public:
	virtual std::string GetName() { return "EntityA" ; }
};
class PlayerA : public EntityA
{
private:
	std::string m_Name;
public:
	PlayerA(const std::string& name)
		:m_Name(name) {}
	std::string GetName() override { return m_Name ; }
};
int main()
{
	EntityA* ea = new EntityA();
	std::cout << ea->GetName() << std::endl;
	PlayerA* pa = new PlayerA("Cherno");
	std::cout << pa->GetName() << std::endl;
	EntityA* entitya = pa;
	std::cout << entitya->GetName() << std::endl;
}

Pure Virtual Function P29 代码没试

P28例子中将 EntityA 修改为

class EntityA
{
public:
	virtual std::string GetName() = 0;//纯虚函数
};

Pure Virtual Function 要求子类(subclass)必须实现该函数(Pure Virtual Function force subclass implement it own definition for the function)

含有纯虚函数的类不能 实例化

In OOP programming it is quite commen for us to create a class that consists only of unimplemented methods and then force a subclass to actually implement them, this is something that ofen referred to as interface(c++抽象类)

Interface: A class that only consists of unimplemented methods ,it is not acutally possible to instantiate a interface class(抽象类)

Visibility in C++  P30

private: Only* this class can access   *A friend can acess also

protected: This class or subclass can access 

Array in C++ P31

数组大小必须在编译时定义,但是有个例外如下

int example[5]  
//或者下面方法
static constexpr int size =5;
int example[size]

String P32 P33 (有时间再看一遍)

  • string作为 形参使用  const string&  name  这种形式
  • 注意“Cherno”不是std::string类型,而是一个const char array(数组) (char array字符串),使用std::string("Cherno")将其转换为string类型
  • “Cherno”这个字符串有7个字符,“Cherno\0"

CONST in C++ P34

const int MAX_AGE = 90;
const int* a = new int;//const int* 这种定义下 指针所指向地址里的内容是const 不可改变的 可以改变指针  int const* a与之相同
*a = 2;//报错
a = (int*)&MAX_AGE;//不报错,指针可改变,新地址中也是const int类型

int* const a =  new int;//int* const 这种定义下 指针是const的 不可改变指针 可以改变指针所指向地址的内容
*a = 2;//不报错,指针指向地址中的内容可以改变
a = (int*)&MAX_AGE;//报错,指针不可改变

//在类中使用const
class Entity
{
private:
    int m_X, m_Y;
    mutable int var;
public:
    int GetX() const  //正常情况下 在const 函数中不允许修改成员变量
    {
        var = 2; //由于var是mutable的 所以可以在const函数中修改 
        return m_X;
    }
}
void PrintEntity(const Entity& e)  //const引用作为形参
{
    std::cout << e.GetX() << std::endl;  //由于e是const的 则e.GetX()函数也必须是const 这样才能保证该引用不会修改e中的成员变量
}

The  Mutable Keyword in C++ P35

  • P34中的用法
  • 在lambda中使用,非常少见

Member Initializer Lists in C++ (成员初始化列表)  P36

  • 成员列表初始化必须按照类内变量的定义顺序,否则会报错
  • 建议使用成员列表初始化成员变量,否则在特定情况下(比如:成员变量是另一个类)会出现成员变量被两次初始化的情况。

Ternary Operators in C++ P37

s_Speed = s_Level  >5 ? 10 : 5;         //s_Level >5 则 s_Speed=10 否则 s_Speed=5
s_Speed = s_Level  >5 ? s_Level > 10 ? 15 : 10 : 5; // 10 > s_Level >5 则 s_Speed=10 ,s_Level < 5 s_Speed=5 ,s_Level > 10  s_Speed=15 不建议如此使用

How to CREATE  INSTANTIATE  OBJECTS in C++ P38

  • Stack and Heap
  • Object   的作用域
#include 
#include 

using String = std::string

class Entity
{
private:
    m_Name;
public:
    Entity() : m_Name("Unknown") {}
    Entity(const String& name) : m_Name(name) {}
    const String& GetName() { return m_Name; }
}
int main()
{
    Entity* e;
    Entity entity = Entity("Cherno); 
    Entity entity("Cherno");//这两种方式写法不同效果一样, 将entity建立再stack上 自动管理内存
    e=&entity;//需不需要删除e????
    
    Entity* entity = new Entity("Cherno"); //使用new生成的对象(object)建立在heap上,需要程序员手动删除
    e=entity;
    std::cout << entity->GetName() << std::endl;//类的指针使用->(arrow operator)使用类内方法
    std::cout << (*eintiy).GetName() <

The NEW Keyword in C++ P39

  • new  allocate continuous memory on the heap

int main()
{
    int* b = new int[50];//一个int 4 bytes int[50] 一共200 bytes
    
    Entity* e = new Entity[50];//Entity 的大小 乘以 50
    Entity* e = new Entity();//new 分配内参的同时调用默认构造函数
    Entity* e = (Entity*)malloc(sizeof(Entity));//与new效果相同,但是不调用默认构造函数
    delete e;//使用结束后要删除,delete 会调用析构函数(destructor)
    free(e);//c函数,使用delete时会调用free(),free不会调用析构函数
    delete[] b;//如果 new使用了[],则delete时也要加上[]
}

Implicit Conversion and the Explicit Keyword in C++  P40

  • implicit 与 explicit 是用来修饰构造函数的
  • 构造函数默认是implicit的
  • 如果使用explicit修饰构造函数,则无法进行隐式转换。见代码
class Entity
{
private:
    std::string m_Name;
    int m_Age;
public:
    Entity(const std::string& name)
        : m_Name(name), m_Age(-1) {}
    
    explicit Entity(int age)
        : m_Name("Unknown"), m_Age(age) {}

int main()
{
    Entity a = Entity("Cherno")
    Entity a("Cherno");//推荐
    Entity a = "Cherno";//implicit conversion OR implicit constructor
    Entity b = Entity(22);
    Entity b(22);//推荐
    Entity b=22;//报错,因为构造函数已经是explicit的
}

OPERATORS and OPERATORS OVERLOADING in C++ P41

class EntityB
{
private:
	std::string m_Name;
	int m_Age;
public:
	EntityB(const std::string& name)
		: m_Name(name), m_Age(-1) {}
	explicit EntityB(int age)
		: m_Name("Unknown"), m_Age(age) {}
};
struct Vector2
{
	float x, y;
public:
	Vector2(float x, float y)
		: x(x), y(y) {}
	Vector2 Add(const Vector2& other) const
	{
		return Vector2(x + other.x, y + other.y);
	}
	Vector2 Multiply(const Vector2& other) const
	{
		return Vector2(x * other.x, y * other.y);
	}
	Vector2 operator+(const Vector2& other) const
	{
		return Add(other);
	}
	Vector2 operator*(const Vector2& other) const
	{
		return Multiply(other);
	}
	bool operator==(const Vector2& other) const
	{
		return x == other.x && y == other.y;
	}
	bool operator!=(const Vector2& other) const
	{
		return !(*this == other);
	}
};
std::ostream& operator<<(std::ostream& stream, const Vector2& other)
{
	stream << other.x<< ',' << other.y << std::endl;
	return stream;
}
int main()
{
	Vector2 position(4.0f, 4.0f);
	Vector2 speed(0.5f, 0.5f);
	Vector2 powerup(1.1f, 1.1f);

	Vector2 result1 = position.Add(speed.Multiply(powerup));
	Vector2 result2 = position+(speed*(powerup));
	
	std::cout << result2 << std::endl;
}

The this keyword in C++ P42

class EntityC
{
public:
	int x, y;

	EntityC(int x, int y)
	{
		this->x = x;
		this->y = y;
	}
	int GetX() const
	{
		const EntityC& e = *this;
		return e.x;
	}
};

Object Lifetime in C++ (Stack Scope Lifetime) P43

scope: {}curly bracket { 与 } 之间就是一个scope

SMART POINTERS in C++ (std::unique_ptr    std::shared_ptr   std::weak_ptr) P44

  • std::unique_ptr不能复制,赋值
  • std::shared_ptr可以用来赋值
  • std::weak_ptr可以用来赋值但是reference count 不计数
//我操了   妈个比 写完了没保存 有时间再写吧  气死我了 妈个比的 草草草草

Coping and Copy Constructor in C++ P45

  • 浅拷贝(Shallow copy)
  • 深拷贝(Deep copy)  类的成员变量有指针变量时,就需要写深拷贝构造函数(copy constructor) !
  • 当不使用引用作为形参时,会在形参传入函数内时进行copy。如果形参是一个class类型时,会调用构造函数
  • always pass your objects by constant reference  ALWAYS !!!
class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size];//这个写法最后会显示乱码 因为字符串的结尾没有\0,因此无法正确的找到字符结束标志
		memcpy(m_Buffer, string, m_Size);
	}
	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;
}
int main()
{
	String string("Cherno copy");
	std::cout << string << std::endl;
}

修改成如下

class String
{
private:
	char* m_Buffer;
	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';//or = 0
	}
	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;
}
int main()
{
	String string("Cherno copy");
	std::cout << string << std::endl;
}
class String
{
private:
	char* m_Buffer;
	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';//or = 0
	}
	~String()
	{
		delete m_Buffer;
	}
	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;
}
int main()
{
	String string("Cherno copy");
	String second=string;//这里在程序运行结束后调用析构函数时会报错
	//这种赋值方式是浅拷贝(shallow copy)second与string指向同一个内存地址,
    //当程序结束时string已经调用析构函数将内存释放掉了,当second调用析构函数时该地址里已经是空的了因此会报错
    //浅拷贝只将指针拷贝走了,因此scond与string的m_Buffer 指针值相同,也就是指针指向的地址相同
    std::cout << string << std::endl;
	std::cout << second << std::endl;
}

The Arrow Operator inC++ P46

-> equal to  (* ptr).

可以在类内重载->实现 class-> 

本来不想试视频里的代码了,但是! 这里大牛写了一个十分炫技的骚操作,忍不住记下来

//这段代码输出Vector3成员变量的偏移,x 0   y 4   z  8
class Vector3
{
public:
	float x, y, z;
};
int main()
{
	long offset = (long)&((Vector3*)nullptr)->y;
	std::cout << offset << std::endl;
}

Dynamic  Arrays in C++  (std::vector)  P47

  • 当 vector 新增的元素超过其初始定义大小时就会,创建一个新的vector 将原有数据拷贝到新vector中并删除旧vector
  • a.clear() 清除a中所有变量   
  • a.erase(a.begin()+i) 删除a中第i个变量

Optmizing the usage of std::vector P48

  • vertices.push_back(Vertex(4, 5, 6));  首先在main函数的stack中先构造了Vertex的临时变量,然后拷贝到vector所在的内存地址中
  • 2个push_back产生3个copied (1+2)     3个push_back产生6个copied (1+2+3)    4个push_back产生10个copied(1+2+3+4)
  • 可以总结出 每push_pa
  • ck一次vector 都会将原有数据拷贝到新vector中加上本次新增的变量

优化策略:直接将Vertex构造在vector(vertices)所在的内存中。

方法1:使用.resrve()

struct Vertex
{
	float x, y, z;
	Vertex(float x, float y, float z)
		: x(x), y(y), z(z)
	{
			
	}
	Vertex(const Vertex& other)//拷贝构造函数
		:x(other.x), y(other.y), z(other.z)
	{
		std::cout << "Vertex Copied!" << std::endl;
	}
};
int main()
{
	std::vector vertices;
	vertices.reserve(4);//假如已经知道了要添加多少变量,则可以提前规定好vector大小避免重复制
	vertices.push_back( {1,2,3} );
	vertices.push_back({ 4,5,6 });
	vertices.push_back(Vertex(4, 5, 6));
	vertices.push_back(Vertex(7, 8, 9));
	std::cout << vertices[2].z << std::endl;

 }
//这种方式不行,一样是10个copied
	vertices.reserve(1);
	vertices.push_back( {1,2,3} );
	vertices.reserve(vertices.size()+1);
	vertices.push_back({ 4,5,6 });
	vertices.reserve(vertices.size()+1);
	vertices.push_back(Vertex(4, 5, 6));
	vertices.reserve(vertices.size()+1);
	vertices.push_back(Vertex(7, 8, 9));

方法2:使用empalce_back()

struct Vertex
{
	float x, y;
	std::string	z;
	Vertex(float x, float y, std::string z)
		: x(x), y(y), z(z)
	{
			
	}
	Vertex(const Vertex& other)
		:x(other.x), y(other.y), z(other.z)
	{
		std::cout << "Vertex Copied! " << z < vertices;
	vertices.reserve(3);//注释掉后emplace_back也会调用拷贝构造函数
	vertices.emplace_back(Vertex(1, 2, "test1"));//这种方式依然会调用拷贝构造函数
	vertices.emplace_back(4, 5, "test2");
	vertices.emplace_back(7, 8,	"test3");
}

 Using Libraries in C++ (Static Linking) P49

笔者使用cmake管理静态链接库,此处不赘述 可参考:《CMake实践》笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE_Primeprime的专栏-CSDN博客

set(xxx_LIB_DIR   ${CMAKE_SOURCE_DIR}/xxx/xxx)
target_link_directories(${xxx_LIB_DIR})
target_link_libraries(xxx   xxx.lib)

Using Dynamic Libraries in C++ P50

set(xxx_LIB_DIR   ${CMAKE_SOURCE_DIR}/xxx/xxx)
target_link_directories(${xxx_LIB_DIR})
target_link_libraries(xxx   xxxdll.lib)

Making and Working with Libraries (Multiple Projects in Visual Studio) P51

cmake 管理多工程项目 lib项目 又有exe项目 则内部调用lib时

内部lib直接写target name就OK,但是必须在同一个proj下

How to Deal with  Multiple Return Values in C++ P52

  1. 引用作为形参 可以返回不同类型
  2. array
  3. vector
  4. tuple 可以返回不同类型  c++之元组std::tuple常见用法 - mohist - 博客园 (cnblogs.com)
  5. pair   C++ pair的基本用法总结(整理)_sevenjoin的博客-CSDN博客_c++ pair
  6. struct

wsting wstring包含汉字,wcout如何输出_qq_24127015的博客-CSDN博客_wstring怎么输出

Templates in C++ P53

template  或者  template 推荐第一种写法  

template does not really exist untill U call it 

一个特殊的用处:get parameter at compile time

template
void PrintArray(std::array& data)
{
//	for (size_t i = 0; i  data;
	data[0] = 0;
	data[1] = 1;
	data[2] = 2;
	data[3] = 3;
	data[4] = 4;
	PrintArray(data);

Stack vs Heap  Memory in C++ P54

stack and heap: 栈与堆  堆(heap)和栈(stack)有什么区别?? - 割肉机 - 博客园

这里说的栈与堆是操作系统中的概念与数据结构中的栈与堆不同。

heap:程序员操作,由malloc,memset之类函数分配的空间所在地。地址是由低向高增长的。  一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收
stack:编译器自动操作,以及函数调用的时候所使用的一些空间。地址是由高向低减少的。

Macros in C++ P55

The auto keyword in C++ P56

Static Arrays in C++ (std::array) P57

std::array data;

template
void PrintArray(std::array& data)
{
//	for (size_t i = 0; i  data;
	data[0] = 0;
	data[1] = 1;
	data[2] = 2;
	data[3] = 3;
	data[4] = 4;
	PrintArray(data);

 Function Pointers in C++ P58

函数名是指针,既然是指针就可以作为形参(回调函数)   例:void (* FunctionPtr)(int,std::string)

void PrintValue(int value)
{
	std::cout << "value:" << value << std::endl;
}
void ForEach(std::vector& values, void (*func)(int))
{
	for (int value:values)
	{
		func(value);
	}
}

int main()
{
	std::vector values = { 1,2,3,4,5 };
	ForEach(values, PrintValue);
}

Lambda  in C++

[ ] capture group  cppreference.com

void PrintValue(int value)
{
	std::cout << "value:" << value << std::endl;
}
void ForEach(std::vector& values, void (*func)(int))
{
	for (int value:values)
	{
		func(value);
	}
}

int main()
{
	std::vector values = { 1,2,3,4,5 };
	ForEach(values, PrintValue);
    //lambda 用法
	ForEach(values, [](int value) {std::cout << "lambda:" << value << std::endl; });
}

Namespace in C++ P60 P61

Never Ever Use using namespace in header file  (just in scope {} ) 

Threads in C++ P62

#include

static bool s_Finished = false;
void DoWork()
{
	using namespace std::literals::chrono_literals;
	std::cout << "Started thread ID = " << std::this_thread::get_id() << std::endl;
	while (!s_Finished)
	{
		std::cout << "Working...\n" ;
		std::this_thread::sleep_for(0.5s);//0.5s 是字面常量,C++可以定义字面常量
	}
}

void DoWork1()
{
	using namespace std::literals::chrono_literals;
	std::cout << "Started thread ID = " << std::this_thread::get_id() << std::endl;
	while (!s_Finished)
	{
		std::cout << "Another Working...\n" ;
		std::this_thread::sleep_for(0.5s);
	}
}
int main()
{
	std::thread worker(DoWork);
	
//下面这个for循环会先执行 然后才会进入 worker 线程中for (size_t i = 0; i < 20; i++)
	{
		std::cout << "This is out of Therad\n";
	}
	std::thread worker1(DoWork1);
	std::cin.get();
	s_Finished = 1;
	worker.join();//不加join() 退出程序时会报警 abort() 被调用
	worker1.join();
	std::cout << "Finished\n";
	std::cout << "Started thread ID = " << std::this_thread::get_id() << std::endl;
}

Timing in C++ P63

包含头文件#include

方式1:直接使用

int main()
{
	using namespace std::literals::chrono_literals;
	auto start=std::chrono::high_resolution_clock::now(); 
	//std::chrono::steady_clock::time_point start= std::chrono::high_resolution_clock::now();
	std::this_thread::sleep_for(1s);
	auto end = std::chrono::high_resolution_clock::now();
	std::chrono::duration duration = end - start;
	std::cout << duration.count() << "s" << "\n";
}

方式2:利用类的构造函数与析构函数 

struct Timer
{
	//std::chrono::time_point start, end;
	std::chrono::steady_clock::time_point start, end;
	std::chrono::duration duration;
	Timer()
	{
		start = std::chrono::high_resolution_clock::now();
	}
	~Timer()
	{
		end = std::chrono::high_resolution_clock::now();
		duration = end - start;
		std::cout << "Timer took " << 1000.0f * duration.count() << "ms\n";
	}
};
void Function()
{
	Timer timer;
	for (size_t i = 0; i < 10; i++)
	{
		std::cout << "Hello chrono\n";
	}
}
int main()
{
	Function();
}

Mutipledimensional Arrays in C++ P64

指向指针的指针 二维指针或者二维数组(int**)运行速度要比 一维指针速度慢很多(int*)  因为二维指针指向的地址在内存中不是连续的(指针在内存中是在连续地址存放的)要查询指针表才能知道指针指向哪里,可以使用一维指针来优化二维数组,详见下例   Timer 类 见上节

void a2d()
{
	Timer timer;
	int** a2d = new int* [5];
	for (size_t i = 0; i < 5; i++)
	{
		a2d[i] = new int[5];
		for (size_t j = 0; j < 5; j++)
		{
			a2d[i][j] = 2;
			std::cout << a2d[i][j] << " ";
		}
		std::cout << "\n";
	}
	for (size_t i = 0; i < 5; i++)
	{
		delete[] a2d[i];
	}
	delete a2d;
}
void a2dIn1D()
{
	Timer timer;
	int* a2d1 = new int[5 * 5];
	for (size_t i = 0; i < 5; i++)
	{
		for (size_t j = 0; j < 5; j++)
		{
			a2d1[i * 5 + j] = 1;
			std::cout << a2d1[i * 5 + j] << " ";
		}
		std::cout << "\n";
	}
}
int main()
{
	a2d();
	a2dIn1D();
	Function();
}

结果: 速度提高一倍啊 

c++ 学习笔记_第3张图片

Sorting in C++ P65

#include
#include
int main()
{
	std::vector values1 = { 3,5,6,2,4,1 };
	std::sort(values1.begin(), values1.end(), std::greater());
	for (int value : values1)
	{
		std::cout << value << "\n";
	}
	//使用lambda 代替greater()
	std::sort(values1.begin(), values1.end(), [](int a, int b) {return a < b; });
	for (int value : values1)
	{
		std::cout << value << "\n";
	}
}

Type Punning in C++ P66

将一段地址强制转换为另一种类型地址,不推荐使用

int a=50;
double b=*(double*)&a

一个小例子:输出 2  3

struct EntityD
{
	int x, y;
	int* GetPosition()
	{
		return &x;
	}
};
int main()
{
	EntityD entityD = { 3,5 };
	int* positionD = entityD.GetPosition();
	positionD[0] = 2;
	positionD[1] = 3;
	std::cout << entityD.x << "  " << entityD.y << "\n";
}

Unions in C++ P67

union中 不同变量名字占用 相同地址  例子略

Virtual Destructors in C++ P68

基类中的析构函数最好要定义成为virtual ,这样可以允许在使用派生类实例(instance) 分配(assign)给 基类类型后,在删除该实例时调用 基类的 析构函数  Base* poly = new  Derivate() 

Casting in C++ P69  P73

  • c风格cast  (int)
  • c++风格cast    static_cast ()   dynamic_cast();
  • dynamc_cast<> 会进行转换检查,如果cast的类型与源数据类型不匹配,则返回nullptr

 Condition and Action Breakpoints in C++ P70

visual studio 骚操作

Safety in modern C++ and how to teach it P71

bababa... 

Precompiled Headers in C++ P72

PCH  将常用的 并且不会修改的  头文件放在同一个 文件当中,编译成二进制文件

Benchmarking in C++ P74

balabala...

Structure Binding in C++ P75

C++ 17新特性

tuple   and  pair   :    C++17 之 "结构绑定"_ding_yingzi的博客-CSDN博客

你可能感兴趣的:(c++,openGL,visualstudio,c++,学习,开发语言)