type
status
slug
summary
tags
category
password
date
icon

Buzzwords

  • encapsulation 封装
  • inheritance 继承
  • polymorphism 多态
  • overriding 覆盖
  • interface 接口、界面
  • cohesion 内聚
  • coupling 耦合
  • collection classes 容器
  • template 模版
  • responsibility-driven design 责任驱动

c++ improvements

Data abstraction Access control Initialization & cleanup References Function overloading Streams for I/O Name control Operator overloading More safe and powerful memory management Templates Exception handling

Format output

Manipulators are special functions that can be included in the I/O statement to alter. the format parameters of a stream. endl is one of the manipulators.
Create a string & alter string
search string

container

What is STL

STL = Standard Template Library Part of the ISO Standard C++ Library Data Structures and algorithms for C++
 

拷贝赋值运算符

假如我们有两个 container 的实例,那么如果两个实例相等,会发生什么事情?
那么可以很清楚的发现,这两个容器现在指向同一块内存
值得注意的是,这样的赋值实际上本质上是一种共享,并非真正的建立了一个副本
这个例子演示了一个重载 operaor= 的例子,将from中指向的内容拷贝了一份,而非简单的拷贝指针
值是一样的,深拷贝的概念
c++中允许我们进行重新定义 重载赋值运算符
🦄
在一个有运算符的表达式中,如果至少一个操作符是某个类的对象1,则由重载解析查找对应的函数。例如 x = y; 就会被视为 x.operator=(y); 进行查找。
导致原来的val中的东西都没有了
进行防止自我拷贝的处理:
c++允许我们使用operator 进行运算符重载
结合函数重载,我们也容易理解,operator= 同样可以有重载。例如:

运算符重载

既然 operator= 可以重载,那么其他运算符可不可以重载呢?答案是肯定的。C++ 希望表达方式是灵活且自由的;对于自定义类型,C++ 希望人们能写出 F = M * A,而非 assign(F, mul(M, A))
事实上,C 语言的运算符就在一定程度上做了「重载」。回顾上一节的定义,重载的含义是同一个函数(根据参数列表不同)具有不同的行为。例如,* 运算符作为单目运算符时是取值运算符,而作为双目运算符时表示相乘;+ 运算符在两个算术类型之间表示求和,而对于 ptr + i 时其实表示 ptr + i * sizeof(A),其中 ptr 的类型是 A*
而 C++ 允许用户重载大多数的运算符从而提高代码的简洁性和可维护性。
考虑一个存放 M * M 大小矩阵的类 Matrix
int中没有运算符built-in的重载
此时,如果我们写 m1 * m2,其实就等价于 m1.operator*(m2),就调用我们写的重载了!
这样的实现方式确实能够实现上述操作,但是它限制了我们只能写出 Matrix * int 而不能写出 int * Matrix,因为后者被解释为 int::operator*(Matrix),但是 int 中并没有这样的重载(C++ 也不希望支持给内部类型增加新的运算2
如何解决这个问题呢?事实上,运算符重载也可以放在全局,例如:
如何解决这个问题呢?事实上,C++ 允许一个类的定义中给一个外部的函数3「授予」访问其 private 成员的权限,方式是将对应的函数在该类的定义中将对应的函数声明为一个 友元 (friend)
🦄
注意:
友元只是一种权限授予的声明,友元函数并非类的成员。因此它并不受 access-specifier 的影响。
当然,还可以这样进行解决:
其他大多数运算符也能重载。对于一元运算符(如作为正负号的 +-,以及 !~++-- 等),@x 会调用 x.operator@() 或者 operator@(x)。如 -x 会调用 x.operator-() 或者 operator-(x)

STL

STL包括算法,容器,迭代器
容器和算法都可以使用迭代器进行无缝的连接
几乎所有的代码都使用了模版类和模版函数的方式
使用STL的好处:
  1. STL是C++中的一部分
  1. STL是数据结构和算法的分离
    1. STL中的vector容器中,可以放入元素,技术数据类型变量,元素地址
  1. 不需要思考STL具体实现的过程,只需要熟练使用STL就可以了
  1. STL具有高可重用性,高性能,高移植性,跨平台的特点
    1. 跨平台
    2. 高移植性
    3. 模版类和模版函数的方式
    4. 高性能,例如map可以高效的进行查询检索,使用红黑树的变体进行实现
    5. 红黑树是平衡二叉树的一种
容器的分类:
  • 序列形容器
    • 取决于插入时机和地点
    • 和元素值无关
    • 每个元素都有固定的位置
    • vector deque list queue
  • 关联式容器
    • 和插入顺序无关
    • 取决于特定的排序准则
    • set multiset map multimap

vector

vector是C++标准模板库(STL)中一个非常重要和常用的序列容器。它是一种动态数组,可以在常数时间内随机访问元素。
尾部添加和删除元素比较容易但是中间比较费时
下面是vector的一些主要用法:
  1. 构造函数:
      • vector<int> v; //创建空vector
      • vector<int> v(10); //创建初始大小为10的vector
      • vector<int> v(10, 1); //创建初始大小为10且值全为1的vector
      • vector<int> v1(v2); //用v2创建v1
      • vector<int> v(arr, arr+5); //从数组arr中前5个元素创建vector
  1. 元素访问:
      • v[i]; //访问第i个元素
      • v.front(); //访问首元素
      • v.back(); //访问尾元素
  1. 迭代器:
      • v.begin(); //返回首元素迭代器
      • v.end(); //返回尾端的迭代器
      • v.rbegin(); //返回最后元素的反向迭代器
      • v.rend(); //返回首元素的反向迭代器
  1. 容量:
      • v.size(); //返回实际元素个数
      • v.capacity(); //返回总容量
      • v.resize(n); //改变实际元素个数为n
      • v.reserve(n); //将总容量预留为n
  1. 修改:
      • v.push_back(x); //在尾部添加一个x
      • v.pop_back(); //删除尾元素
      • v.insert(it, x); //在迭代器it处插入x
      • v.erase(it); //删除迭代器it所指元素
      • v.clear(); //清空所有元素
  1. 其他:
      • v1 = v2; //直接赋值拷贝
      • v1 == v2; //判断两vector相等
      • sort(v.begin(), v.end()); //对vector排序
vector支持随机访问,能高效地访问和修改任意位置元素。但在中间插入或删除元素时,需要移动后续元素,因此效率较低。它在尾部插入和删除效率很高。当事先知道存储数据量的上限时,可以通过reserve来减少vector的内存重新分配次数。

deque

deque是C++标准模板库(STL)中的一个容器适配器,它提供了一种双端队列的实现。deque可以高效地在头部和尾部进行插入和删除操作,与vector相比,deque在中间进行插入和删除操作的效率较低。
使用deque的主要优点包括:
  1. 双端访问: 可以高效地在两端进行插入和删除操作。
  1. 空间高效利用: 与vector相比,deque通常会分散在不同的内存块中,更好地利用内存。
  1. 内存利用灵活: 当内存不足时,deque会分配新的内存块,因此不需要像vector那样一次性地申请大量内存。
下面是一些常用的deque操作:
  1. 构造函数:
      • deque<int> deq; // 默认构造一个空deque
      • deque<int> deq(10); // 构造一个初始大小为10的deque
      • deque<int> deq(10, 1); // 构造一个初始大小为10且初始值为1的deque
  1. 访问元素:
      • deq.front(); // 访问第一个元素
      • deq.back(); // 访问最后一个元素
      • deq[i]; // 访问第i个元素
  1. 插入元素:
      • deq.push_front(x); // 在前端插入元素x
      • deq.push_back(x); // 在尾部插入元素x
  1. 删除元素:
      • deq.pop_front(); // 删除第一个元素
      • deq.pop_back(); // 删除最后一个元素
  1. 其他操作:
      • deq.size(); // 获取元素个数
      • deq.empty(); // 判断是否为空
      • deq.clear(); // 清空所有元素
deque常用于需要高效进行头尾插入删除的场景,如实现一个双端队列或栈。它也可以作为一般容器使用,但中间插入删除操作效率较低。
 
NLP自然语言处理Python
Loading...
fufu酱
fufu酱
一个爱折腾的大学生
公告
👋
欢迎 欢迎来到fufu酱的blog! 💞️我是22级浙江大学竺可桢学院计算机科学与技术专业的学生 一个爱折腾的大学生 🌱我会在这个网站上更新我的笔记和工具分享 🌈目前all in MLLM 📫你可以用下面的方式联系到我
🍀
今後ともよろしくお願いします