# cpp_develop **Repository Path**: guluo123/cpp_develop ## Basic Information - **Project Name**: cpp_develop - **Description**: Develop of c++. - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-12-03 - **Last Updated**: 2025-12-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 2025.12记录 ## 12.6学习记录 ### 1、.md文档的编写 标题与分级:#(#后面要加space才能算命令); 文档中进行:**加粗**; 段内进行代码的引用 :``std::cout << Hello World << std::endl;``; 整段的代码引用:第一段后面加上对应的文件,可以显示使用的代码风格。 ```cpp #include void main(void) { std::cout << "Hello World" << std::endl; } ``` - list:**-**可以用来排列,也要记得加space。 [链接,这个链接可以查看一些md的用法](https://stackedit.cn/app#) 剩下的就省略了。 ### 2、构造函数的学习: 构造函数的使用: ```cpp class Entity_12_6 { public: float x, y; Entity(){}//如果函数内不加入参数,则默认初始化为0. Entity(float set_x, float set_y)//带参数版本,也是一种函数重载; { x = set_x; y = set_y; } }; ``` 构造函数在创建一个新的实例对象时便会被调用。 ### 3、析构函数: 析构函数: ```cpp ~Entity() { //some code. eg: free memory. } ``` ### 4、继承: ```cpp class Entity{};//父类 class Player : public Entity//子类,继承父类的所有public { }; ``` ### 5、虚函数: 会影响部分性能,如果追求极致内存最好不用。 ```cpp class parent { public: virtual void Print(){} }; class child : public parent { public: void print() override {} }; ``` ## 12.7学习记录: 未学习,看了一天的房。 ### 学习如何解决git合并的冲突。 > commit --amend 完之后加上pull再进行push能够解决冲突,如果说有冲突,需要修改 <<< 到 ==== 或者 >>>> 到 ==== 之间的内容。 ## 12.8学习记录: ### 1、纯虚函数: 可以看成是一种接口,强制子类重写该函数。此时该父类函数无法被初始化为一个实例,其子类需要重写完虚函数后才能够被初始化为一个实例。 ```cpp class parent { virtual void func() = 0; }; class child : public parent { void func() override {}; }; ``` > Example : test_12_8 ### 2、可见性 c++中共有三种可见性``private``,``protected``和``public``。其中,``protected`` 修饰的内容可以被子类访问,但不能被外界访问。 ## 12.9学习记录: ### 1、字符串: 字符串以 ``0`` 来结束。如果手动定义一个字符串, `` char name[] = {'n', 'a', 'm', 'e'};`` ,最后没有0,则会导致字符串乱码,也就是字符串无法被读取到正常的长度。 引入 ``string`` 库可以获取字符串的大小等。 传递字符串时,通常采取 ``const std::string& string`` 的方式来传递字符串参数,因为直接使用 ``std::string string`` 意味着复制了一个字符串,会导致代码运行速率下降。 ### 2、字符串字面量: 就是 ``""`` 之间的内容,如 ``"name"`` 。字符串字面量只保存在内存中的**只读区域**。 ``strlen()``会得到``()``内从开始到``\0``之间的字符个数。 使用 ``const char* ex = R"()";``可以方便地打印出多段内容。 ### 3、const: 理解**指针常量**和**常量指针**。 在类中,``const``加在函数最后表示该函数不会修改类中的任何变量。例如: ```cpp class Entity { private: int x, y; //指针情况:int *x, *y; public: int Get_x() const { return x; } }; ``` 常量引用只能引用带有 ``const`` 的内容。``const`` 修饰的类,只能够调用含有 ``const`` 的函数。( [34P] : 11min左右) ### 4、mutable: mutable应用的两种情景: - 与``const``一起使用。在变量前使用 ``mutable`` 后可以在const修饰的函数内更改该变量的值。例如:``mutable int var;`` - 与lambda一起使用。(很少使用) ### 5、成员初始化列表: **需要按顺序初始化成员变量**; 如果未使用成员初始化列表而是在构造函数中直接赋值,就相当于创建了两次变量,会对性能产生一定的影响。 例: ```cpp class Entity { private: int x, y; public: Entity() : x(0), y(0) { } }; ``` ## 12.11学习记录: ### 创建并初始化c++对象: 简单来说,就是选择合适的创建方式,在堆上创建(用``new``来分配内存)或者在栈上创建 ### new关键字: ``new`` 关键字不仅在堆上分配空间,还会**调用构造函数**。 相比较而言 ``malloc()``只是在堆上分配了内存。 使用了``new``后必须使用 ``delete`` 来释放内存。 ### 隐式构造函数和隐式转换: ``explicit``会禁止隐式转换。 ## 12.12学习记录: ### 运算符重载 例如:`` int operator+(int a) { return Add(a);}`` 同时 `` << ``也是一个重载过的运算符。可以解释``void test_12_11(void)``出现的一个问题: 在 ``<<`` 右侧,不能直接使用**类**,如果需要使用,则需要在上面进行重载。 ## 12.13学习记录: ### this 关键字 ``this`` 是一个指向当前对象实例的指针。 ### 智能指针 需要包含头文件```` ``unique_ptr``:作用域智能指针,不能够被复制。开销较小。 ``shared_ptr``: 共享指针,内部有一个计数器,可以记录有多少指针指向这块内存。只有当所有指针都不再指向这块内存时才会释放该内存。开销较大。 使用 ``std::make_shared/make_unique`` 表示分配内存。其中,make_shared 用一次后,后面再有指针指向同一内存时则不需要再重新make来分配空间。 ### 拷贝与拷贝函数 拷贝构造函数是一个构造函数,当你复制第二个对象的时候,它就会被调用。 如果不需要其默认的拷贝函数,可以直接等于``delete`` ```cpp Srting(const Srting& other) = delete; ``` 尽量总是使用 const & 来传递参数。小对象可以使用值传递。 例子:当函数传参时,如果没有加 & ,那么实际上就是进行了一次复制,会增加开销。 c++默认的拷贝函数是一种浅拷贝。类似于: ```cpp String (const Srting& other) :m_buffer(other.m_buffer), m_bufsize(other.m_bufsize) { } //或者 String(const String& other) { memcpy(this, &other, sizeof(String)); } ``` ## 12.14学习记录: ### 箭头操作符: ``->`` 通常用在指针类引用自己内部的成员。可以进行重构。 使用 `` uintptr_t `` 可以将指针的地址(float *类型)转化为整数。 ### 动态数组(标准模板库) ``std::vector``的使用。存储对象比存储指针更优。工作过程大概可以概括为:首先创建一个数组,随后使用``push_back``加入数组;当数组大小不够时,会从另外的地方重新寻找一片新的能够容纳当前数组的内存,然后将数组复制到新的内存处,然后删掉旧的数组。 作为参数传递时,最好使用引用,避免直接**复制**。 ## 12.15学习记录: ### 动态数组的优化 不使用优化的话,会对对象进行多次复制。 优化1:在已知创建多少个对象的情况下,可以事先分配固定大小的内存。 使用:``vertex.reserve(n)``,在 n 以内,则只会进行创建次数的复制,而不会更多地复制。 优化2:vector 实际上是在main函数中构造,然后复制到实际的vector中。所以我们需要直接在实际的vector中创建。 使用``vertex.emplace_back`` 取代 ``push_back`` ### 库 静态库和动态库的区别:(简单区别) - 静态库指的是这个库会被放到可执行文件exe中。 - 动态库则会在运行时被链接,在运行时载入动态库,然后拉去其中的函数。 ## 12.16学习记录: ### 动态库 静态库是在编译的时候链接,可以进行更多的优化。 而动态库是在启动可执行文件时才进行链接。 ### 多返回值的处理 可以通过 - 引用、指针 - vector数组或者arry数组 - 创造一个结构体。 以及c++提供的方法:元组(tuple)和 pair tuple:是一个类,可以包含n个变量,不关心变量的类型。 ### 模板 可以类比其他语言中的**泛型**,但是有所不同。 模板允许你定义一个可以根据自己用途进行编译的模板。自己定义一套规则,然后让编译器来写代码。 语法: ```cpp template //也可以使用 class T void Func(T value) { /* do something */} ``` 模板未被调用时是不存在的,不会进行语法检查等。只有在被调用时才会被创建。 ## 12.17学习记录: ### 栈和堆 在栈上分配更快一些,因为其只是相当于运行一条CPU语句。 ### 宏 宏在预编译阶段被调用。也就是说机器会在编译前先将宏定义进行解读,随后再进行整个代码的编译。 ### auto关键字 当我们的类型过长时,使用auto可能是一个好的选择。 ## 12.18 ### 静态数组 ``std::array`` 用来处理静态数组的类。需要包含头文件````。 静态数组存储在栈中。静态数组有边界检查,且不会影响性能,还能够返回数组的大小。 ### 函数指针(原始) 将函数看成一个指针变量。一样是 type + name(arg). ### lambda lambda实际上是一种匿名函数,有点像是一次性的函数。 一般用在我们需要使用函数指针的地方。 `` auto lambda = [捕获](传参){函数主体};``,函数主体里记得加``;`` > 补充:可以在网站 [cppreference](https://www.cppreference.com/) 查看c++很多函数的说明,包括lambda。 使用lambda,可能还需要使用std::function。 ## 12.19 ### 命名空间 尽量在一个小的范围内使用命名空间。 命名空间也可以嵌套使用。 ### 线程 需要包含头文件 ```` ### 计算程序运行时间 使用 ````库。 创建一个 struct 的 time 结构体,在函数开始的时候定义,就可以得到整个函数的执行时间。 ## 12.20 ### 多维数组 ## 12.21 ### 配置vscode 1、主题配置 1.moonlight(一种浅色主题) 2.windows opacity(调整透明度) 2、函数截图:codesnap 3、AI编程:lingma(可能copilot也一样,但是我没用过) ### 排序 c++内置的排序函数为 ``std::sort``。复杂度为O(nlogn) 个人理解: **lambda函数的返回值为true时,则交换两个元素**。可以通过设置 a , b 两个值来控制特定字符所在位置。 ### 类型双关 我要把我拥有的这段内存,当作不同类型的内存来对待。我们要做的只是将该类型作为指针,将其转换为另一个指针。 感觉意思就是一种对地址的操作。 ### 联合体union 联合体内的成员共用一块内存。 ### 虚析构函数 当你创建一个基类指针,指向一个派生类对象时,基类析构函数不会被调用。所以你需要在基类中声明你的析构函数为虚函数。 ## 12.22 ### 类型转换 c 语言风格的类型转换是通过在()中添加类型,如 ``(int)a``,来强行转换。 c++风格的类型转换:使用``static_cast(a)``,本质和c语言风格的转换一样,由于使用了英语单词,所以可以更方便程序员进行搜索。 dynamic_cast:会在运行时检查转换是否成功。如果成功,则返回转换后的指针,不成功则返回``NULL``。 ## 12.23 ### 条件和操作断点 对断点的使用,通过右键断点可以选择断点的模式。需要自己去尝试和理解。视频里是叫做 conditions, 可以在不中断程序的情况下对代码进行调试。 ### 预编译头文件 使用预编译头文件可以提高编译速度,程序不会重新再去编译相同的头文件。预编译头文件中最好包含的是不会改变的且常用的头文件。 ### dynamic_cast dynamic_cast 在运行时检查转换是否成功。如果成功,则返回转换后的指针,不成功则返回NULL。它会对转换进行检查,确保转换是有效且安全的。它更像是一个函数,专门用于沿继承层次结构进行的强制类型转换。 ## 12.24 ### 基准测试 可以通过测量函数运行的时间来进行测试。可以使用Timer类。 很奇怪,没办法进行单元测试,时间对不上。-> 感觉是debug的原因,直接运行的话没有什么问题,使用debug会导致后面的时间延长。 ## 12.25 ### 结构化绑定(只针对c++17) ### 如何处理可能存在可能不存在的数据 使用``std::optional``,c++17才有的一种特性。需要包含头文件 ```` 留点尾巴,睡觉了,看完了但是没写代码。