58同城网站建设推广,推广计划书怎么写,网站建设完成情况工作总结,重庆腊肠怎么制作C随心记
C中的 CONST
C中的const是表示不可修改
int main()
{/* 对于变量而言 */// 不可修改的常量const int A 10;// 不可修改的指针指向const int* pointer_0 nullptr;int const* poniter_1 nullptr;// 不可修改指针指向的内容int* const poniter_2 nullptr;
}const也…C随心记
C中的 CONST
C中的const是表示不可修改
int main()
{/* 对于变量而言 */// 不可修改的常量const int A 10;// 不可修改的指针指向const int* pointer_0 nullptr;int const* poniter_1 nullptr;// 不可修改指针指向的内容int* const poniter_2 nullptr;
}const也可修饰函数
class Entity
{
private:int* pointer;int x;
public:/* 对于函数而言 */// 修饰函数使得其权限仅为读取不可写入int GetX() const{// x; 此语句是非法的函数被const修饰后不准更改函数外的变量return x;}// 如果返回的为指针也可以用于修饰指针// 指向内容不可变int* const GetPoniter(){return pointer;}// 指向不可变const int* GetPointer(){return pointer;}// 一次性写最多的合法constconst int* const GetPointer() const{return pointer;}};C中的mutable
和上文的const一样都是关键字但mutable与const相反。mutable意味着可更改的。
class Entity
{
private:mutable int x;int y;
public:Entity(): x(10), y(20){}void ChangeXAndRead() const{x;std::cout The value of X,Y is x , y std::endl;// 这里的输出结果为1120// 当试图修改y的值的时候因为y的值为非mutable修饰所以会报错}
};C中的成员初始化列表
在面向对象的语言中多数程序员喜欢在构造器内初始化成员。在C语法中存在专门初始化成员的功能此功能的优点是避免了在定义成员时被构造当我们定义一个变量时如果这个变量为某个类的实例那么在定义时会调用其构造器当我们赋值时回再次调用构造器这造成了性能的浪费。
class Entity
{
public:std::string x; // 此时调用了string的构造器Entity(){x Hello; // 此时调用了Hello的构造器并把地址给了x}
};// 下面是一个比较直观的例子
class Example
{
public:Exapmle(){std::cout Example created! std::endl; }Example(int x){std::cout Example created with x! x x std::endl; }
};class Entity
{
public:Example example;// 这里会输出Example created!Entity(){example Example(8);// 这里会输出Example created with x! x8}
};这样就输出了两次代表着调用了两次构造器。为了节省性能我们可以使用成员初始化列表语法如下
class Entity
{
private:std::string m_Name;int m_DebugCount;
public:Entity(const std::string Name):m_Name(Name), m_DebugCount(0){}
};上面写了一个有参构造器参变量为常量引用的Name。重点是下面是成员初始化列表用冒号隔开冒号后为要初始化的成员初始化的内容为后面的括号的内容。需要注意的是成员初始化列表需要和成员变量的定义顺序相同这一规则非严格规定但不遵守此规则可能会导致部分成员变量无法初始化每个成员变量之间用逗号隔开
delete的小注意
对于new出来的对象要记得delete。要delete一块数组要用delete[]
int main()
{int* a new int[10];delete[] a; // To delete array areturn 0;
}如果不使用delete[]的话你删的只是指针所指的第一个元素而已。
C的隐式类型转换
C中的类型转换是自动的甚至可以转换到类的构造器中以下为实例。
class Entity
{
private:int m_Age;std::string m_Name;
public:Entity(const std::string name):m_Age(-1), m_Name(name){std::cout Entity constructor with name has called! std::endl;}Entity(int age):m_Age(age), m_Name(Unknown){std::cout Entity constructor with age has called! std::endl;}
};int main()
{Entity e1 12; // 隐式类型转换Entity e2 std::string(Chreno);return 0;
}explicit关键字
由于隐式转换是默认的开发者不希望自己的构造函数被隐式转换就可以添加关键字explicit来强制构造器拒绝隐式转换。例如
class Entity
{
private:int m_Age;std::string m_Name;
public:Entity(const std::string name):m_Age(-1), m_Name(name){std::cout Entity constructor with name has called! std::endl;}explicit Entity(int age):m_Age(age), m_Name(Unknown){std::cout Entity constructor with age has called! std::endl;}
};int main()
{// Entity e1 12; // 此行由于构造器被explicit修饰故报错Entity e2 std::string(Chreno);return 0;
}C中的运算符重载
浅谈一下重载问题其实运算符最简单的四则运算无非就是加减乘除。我们在重载时只要跟编译器说明了这个函数就是在重载就好了我们会用到operator标识一下我们重载的是运算符
struct Vector2
{float x, y;Vector2(float x, float y):x(x), y(y) {}// 运算符重载Vector2 operator(const Vector2 other) const{return Vector2(x other.x, y other.y);}Vector2 operator-(const Vector2 other) const{return Vector2(x - other.x, y - other.y);}Vector2 operator*(const Vector2 other) const{return Vector2(x * other.x, y * other.y);}Vector2 operator/(const Vector2 other) const{return Vector2(x / other.x, y / other.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);}void printSelf(){std::cout Value of x: x ,Value of y: y std::endl;}
};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 res position speed * powerup;result.printSelf();res.printSelf();// result equals resreturn 0;
}再补充一点我们可以重载ostream的运算符来达到输出内容的目的
#include iostreamclass Entity
{
public:int x, y;Entity(int x, int y):x(x), y(y){}};// 2、此时我们就需要重载一下运算符
std::ostream operator(std::ostream stream, const Entity other)
{stream other.x , other.y std::endl;return stream;
}int main()
{Entity e(1, 2);// std::cout e std::endl; // 1、这里肯定不会输出其内容而且也会报错// 3、然后我们再来使用这个运算符std::cout e std::endl;return 0;
}C智能指针
智能指针就是用std::unique_ptr来裹住一个对象相对于原始指针智能指针加了一层壳。将这个对象的栈和堆内存绑定在跳出作用域时自动调用delete方法语法见下
#include iostream
#include memoryclass Entity
{
public:int x, y;Entity(int x, int y):x(x), y(y){std::cout Entity created! std::endl;}~Entity(){std::cout Entity destory by itself std::endl;}};int main()
{{std::unique_ptrEntity entity std::make_uniqueEntity(); // 就一次内存分配更效率std::unique_ptrEntity e(new Entity(1, 2)); // 先Entity()构造分配一次内存再给unique_ptr分内存}std::cout Program is going done~ std::endl;return 0;
}但是unique_ptr不能共享指针给别人从原理上来说这个对象被释放以后手握这个对象的指针也都会嗝屁实际上需要同步。从源码上来看号这个运算符被重载了。 下面看一下shared_ptr一个可以共享的智能指针
#include iostream
#include memoryclass Entity
{
public:int x, y;Entity(int x, int y):x(x), y(y){std::cout Entity created! std::endl;}~Entity(){std::cout Entity destory by itself std::endl;}void print(){std::cout The value of x: x ,y: y std::endl;}
};int main()
{std::shared_ptrEntity e;{std::shared_ptrEntity shared_entity std::make_sharedEntity(); // 性能缘由同上std::shared_ptrEntity shared_entity_new(new Entity(1, 2));e shared_entity;}e-print();std::cout Program is going done~ std::endl;return 0;
}shared_ptr底层实现类似计数器不分享的时候相当于在unique_ptr和计数器0分享一次就会计数器。当计数器为0后再结束生命周期就会delete这个对象本体在堆上否则只是释放了指针本身的内存在栈上。给weak_ptr分享不会增加计数器。
C计算偏移量
计算偏移量在计算机图形学里比较多见先写一下具体过程
#include iostreamstruct Vector3
{float x, y, z;
};int main()
{int offset (int)((Vector3*)nullptr)-y;std::cout offset std::endl;std::cin.get();return 0;
}代码中offset就是偏移量。首先将0或者nullptr强制转化为结构体或类的指针再去通过-调用指针就会根据偏移量偏移到目标的起始位置(这就是我们需要的值)之后取这个位置的地址(因为使用0或者nullptr作为起始地址所以不用再考虑起始地址)用取地址(内存编号为偏移量)再通过(int)强制转换成整数就得到了偏移量
C中优化std vector三个简单方法
我们先来写一段代码实验一下
#include iostream
#include vectorstruct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout Copied! std::endl;}
};int main()
{std::vectorVertex vertices;vertices.push_back({ 1, 2, 3 }); //1号语句vertices.push_back({ 4, 5, 6 }); //2号语句vertices.push_back({ 7, 8, 9 }); //3号语句return 0;
}这段代码中我们规定Vertex结构体每当被复制后就向控制台输出 经过实际运行后这段代码一共输出了 6 行Copied说明在添加到vector时Vertex被复制了六次。以下是流程执行到1号语句时vertices的承载力为0产生新的vertices并将旧的vertices复制到新的vertices中此时输出1次Copied到二号语句承载力不够接着出现新的容器旧的vertices中已经有的Vertex和新的Vertex都会被复制到新的容器中此时复制了两次即输出两次Copied,以此类推三号语句输出了三次Copied最后即输出了123次即6次Copied 这段过程看似在计算机强大算力前不复杂但是当push_back次数多了以后复制次数就会爆炸式增长
解决方案 一
先告诉vector给留多少空间避免了多次复制
#include iostream
#include vectorstruct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout Copied! std::endl;}
};int main()
{std::vectorVertex vertices;vertices.reserve(3); // 预留空间vertices.push_back(Vertex(1, 2, 3));vertices.push_back(Vertex(4, 5, 6));vertices.push_back(Vertex(7, 8, 9));return 0;
}在这里通过reserve告诉vector给我留3个单位的空间运行完毕后仅输出了 3 次Copied即没有新的容器创建
解决方案 二
通过调用类或者结构体的构造器函数括号内为构造器对应参数
#include iostream
#include vectorstruct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout Copied! std::endl;}
};int main()
{std::vectorVertex vertices;vertices.emplace_back(1, 2, 3);vertices.emplace_back(4, 5, 6);vertices.emplace_back(7, 8, 9);return 0;
}此方法效率和法一相同实现机制不同
解决方案 三(二 一)
预留好空间后再使用emplace不会产生任何复制(预留空间实际需求空间)
#include iostream
#include vectorstruct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout Copied! std::endl;}
};int main()
{std::vectorVertex vertices;vertices.reserve(3);vertices.emplace_back(1, 2, 3);vertices.emplace_back(4, 5, 6);vertices.emplace_back(7, 8, 9);return 0;
}此示例Vertex类没有发生复制