编译,链接,动态,静态库:
动态:程序运行时再去进行链接 静态:实现就编译链接好了
如果某个函数是某文件里的,要先用extern去让编译器从其他文件里找;
static用在链接时,意思是此变量或者函数只对本文件可见,对其他文件不可见;
inline可以直接使用此函数
#pragma once表示只文件被包含一次;防止多次include该文件;
char字符串相关;
如图,如果是const char* & ref = a,将会报错,因为数组地址其实是不能改变,是const类型的,由此可以得出,如果要创建一个引用,这个引用的类型也要和原始数据一样,比如
const char* pa = a;
这里的a会 被隐式转换为const char*,所以可以。
const char*& ref = a;
而ref引用实际上与a的原始类型有关,因为a是数组,a所代表的首地址不能改变,所以要const类型的引用;而前一个const其实可以不要,因为我们可以修改,也可以不修改这个引用的地址的数据;
char a[] = "char Test";
const char* pa = "ss";
const char* const& ref = a;
New:
使用new的时候,其实底层是调用了malloc函数,区别在于new创建类对象时,会调用构造函数,而malloc只是返回void类型的指针
隐式构造函数和explict:
构造函数可以隐式调用,隐式转换只会进行一次,explict关键字使其不能隐式调用;
函数符重载:
如图:Vector2 operator+ (const Vector2 &v)可以对+进行重载,在使用该类对象的时候,就可以使用+号来进行运算;
class Vector2{
private:
int x,y;
public:
Vector2 add(int a,int b)
:x(a),y(b){}
Vector2 add(const Vector2& v){
return Vector2(x+v.x,y+v.y);
}
//重载"+"
Vector2 operator+ (const Vector2 &v){
return Vector2(this.x+v.x,this.y+v.y);
}
void main() {
Vector2 speed(2,3);//构建一个vector2
Vector2 position(3,4);//构建一个vector2
Vector2 result =speed+position;//两个vector2进行运算
)
智能指针:
可以自动调用析构函数,delete 指针,释放内存;需要导入头文件,include <memory>;
如图,便创建了两个智能指针,第二种方式更好,注意,智能指针不能隐式调用构造函数;
智能指针不能进行copy,赋值给其他指针,看源码可以发现,其实赋值操作已经被重载删除了;
void main(){
//创建Entity类
class Entity{
private:
int x;
public:
Vector2 (int a)
:x(a){
std::cout<<"create Entity!"<<std::endl;
}
~ Vector2 (){
std::cout<<"Destroy Entity!"<<std::endl;
}
}
std::unique_ptr<Entity> e(new Entity(2)) ;//创建智能指针e
std::unique_ptr<Entity> e0 = std::make_unique<Entity>(3);//另外一种方式创建智能指针e0,出于异常安全考虑,这种方式更好
}
共享指针:
共享指针功能和unique差不多,不过他在创建的时候,会在内存里建一个引用计数内存块,每次进行赋值操作,引用计数加1,离开作用域,引用计数减1,当引用计数为0时,才会释放该指针。而使用std::weak_ptr<Entity> e4 = e1;这种方式赋值,不会使引用计数增加;
和unique一样,不用new方式创建更好,这里是因为share创建的时候,会额外分配一块叫做控制块的内存,用来存储引用计数,如果先new Entity再传给share的构造函数,会有两次内存分配;如果std::shared_ptr<Entity>e3(new Entity(5))这种方式,他就会两者结合,效率更高;
include<iostream>
include<memory>//需要包含该头文件
void main(){
//创建Entity类
class Entity{
private:
int x;
public:
//构造函数
Vector2 (int a)
:x(a){
std::cout<<"create Entity!"<<std::endl;
}
//析构函数
~ Vector2 (){
std::cout<<"Destroy Entity!"<<std::endl;
}
}
std::shared_ptr<Entity>e1 = std::make_shared<Entity>(4);//创建共享指针
std::shared_ptr<Entity>e3(new Entity(5));//创建共享指针
std::weak_ptr<Entity> e4 = e1; //可以进行赋值操作,通过weak类型的,不会使引用计数增加
}
偏移量:
如图:0代表地址从0开始,或者是nullptr,数字几就是从几开始计算偏移量,在游戏或者渲染方面会用到;
#include <iostream>
struct vector3
{
float x, y, z;
};
void main() {
int offst = (int)(&(((vector3*)0)->x));
std::cout << offst << std::endl;
}
Vector:
通常初始容量是1;在push_backl时,会将参数复制到vector所分配的内存中,会有多余的copy操作;如果vector的数据超出了它的大小,会自动扩容,将旧vector里的数据copy一份到新创建的vector;
常用:
vector.size(),返回vector大小
vector.push_back(),添加元素
verteies.reserve(3); 预先设定vector的容量
verteies.clear();清空该vector
verteies.erase(verteies.begin());移除某个元素,参数为迭代器
#include <iostream>
#include <vector>
struct Vertex
{
int x, y, z;
Vertex(int a, int b, int c)
:x(a), y(b), z(c)
{
std::cout<<"调用了构造函数"<<std::endl;
}
Vertex(const Vertex& v)
:x(v.x), y(v.y), z(v.z)
{
std::cout << "coping!" << std::endl;
}
};
std::ostream& operator<<(std::ostream &stream,Vertex& v) {
stream << v.x << "," << v.y << "," << v.z;
return stream;
}
void main() {
std::vector<Vertex> verteies;//创建vector数组
//###########优化#################
verteies.reserve(3); //预先设定vector的容量,
verteies.emplace_back(1,2,3);//传入构造函数的参数列表
verteies.emplace_back(4, 5, 6); //告诉vector在其构建的内存中
verteies.emplace_back(7, 8, 9);//把这些作为参数, 构建一个vertex对象
//这样就可以省去很多复制操作
//##########优化###################/
// verteies.push_back(Vertex(1,2,3));//添加元素
// verteies.push_back(Vertex(4,5,6));//添加元素
// verteies.push_back(Vertex(7, 8, 9));//添加元素
/*for (int i = 0; i < verteies.size(); i++) {
std::cout << verteies[i] << std::endl;
}*/
//增强for循环
for (Vertex& v :verteies) {
std::cout << v<< std::endl;
}
verteies.erase(verteies.begin());//移除某个元素,参数需要为迭代器
verteies.clear();//清空该vector
}