• 2023/9/14 -- C++/QT


    作业:

    仿照Vector实现MyVector,最主要实现二倍扩容

    1. #include
    2. using namespace std;
    3. template <typename T>
    4. class MyVector
    5. {
    6. private:
    7. T *data;
    8. size_t size;
    9. size_t V_capacity;
    10. public:
    11. //无参构造
    12. MyVector():data(nullptr),size(0),V_capacity(0) {
    13. //cout<<"MyVector::无参构造"<
    14. }
    15. //有参构造
    16. MyVector(int count,T val){
    17. size = count;
    18. V_capacity = count;
    19. data = new T[count];
    20. for(int i = 0;i < count;i++){
    21. data[i] = val;
    22. }
    23. //cout<<"MyVector::有参构造"<
    24. }
    25. //析构函数
    26. ~MyVector(){
    27. delete [] data;
    28. data = nullptr;
    29. //cout<<"MyVector::析构函数"<
    30. }
    31. // 定义迭代器类
    32. class MyIterator {
    33. private:
    34. T* ptr;
    35. public:
    36. //有参构造
    37. MyIterator(T* p):ptr(p){
    38. //cout<<"MyIterator::有参构造"<
    39. }
    40. // *重载
    41. T& operator*()const {
    42. return *ptr;
    43. }
    44. // 前置++重载
    45. MyIterator& operator++() {
    46. ++ptr;
    47. return *this;
    48. }
    49. // 后置++重载
    50. MyIterator operator++(int) {
    51. MyIterator temp = *this;
    52. ++ptr;
    53. return temp;
    54. }
    55. // 前置--重载
    56. MyIterator& operator--() {
    57. --ptr;
    58. return *this;
    59. }
    60. // 后置--重载
    61. MyIterator operator--(int) {
    62. MyIterator temp = *this;
    63. --ptr;
    64. return temp;
    65. }
    66. // ==重载
    67. bool operator==(const MyIterator& other) const {
    68. return ptr == other.ptr;
    69. }
    70. // !=重载
    71. bool operator!=(const MyIterator& other) const {
    72. return ptr != other.ptr;
    73. }
    74. };
    75. //begin 函数 返回第一个元素的迭代器
    76. MyIterator begin() {
    77. return MyIterator(data);
    78. }
    79. //end 函数 返回最末元素的迭代器(注:实指向最末元素的下一个位置)
    80. MyIterator end() {
    81. return MyIterator(data + size);
    82. }
    83. //assign 函数 对MyVector中的元素赋值
    84. void assign(size_t num, const T &val ){
    85. for(int i = 0;i < num;i++){
    86. data[i] = val;
    87. }
    88. cout<<"assign 函数"<
    89. }
    90. //at 函数 返回指定位置的元素
    91. T at(int pos){
    92. if(pos < 0 || pos >= size){
    93. throw int(1); //抛出异常
    94. }
    95. return data[pos];
    96. }
    97. //back 函数 返回最末一个元素
    98. T& back(){
    99. return data[size-1];
    100. }
    101. //capacity 函数 返回vector所能容纳的元素数量
    102. size_t capacity(){
    103. return V_capacity;
    104. }
    105. //clear 函数 清空所有元素
    106. void clear(){
    107. size = 0;
    108. }
    109. //empty 函数 判空
    110. bool empty(){
    111. return size == 0;
    112. }
    113. //front 函数 返回第一个元素
    114. T& front(){
    115. return data[0];
    116. }
    117. //pop_back 函数 移除最后一个元素
    118. void pop_back(){
    119. if(empty()){
    120. throw int(2); //抛出异常
    121. }
    122. size--;
    123. }
    124. //push_back 函数 在MyVector最后添加一个元素
    125. void push_back(const T& value) {
    126. if (size == V_capacity) {
    127. // 扩容逻辑
    128. size_t newCapacity = (V_capacity == 0)?1:V_capacity * 2;
    129. T* newData = new T[newCapacity];
    130. for(int i = 0;i < static_cast<int>(size);i++){
    131. newData[i] = data[i];
    132. }
    133. delete[] data;
    134. data = newData;
    135. V_capacity = newCapacity;
    136. }
    137. data[size++] = value;
    138. }
    139. //size 函数 返回Vector元素数量的大小
    140. size_t get_size(){
    141. return size;
    142. }
    143. };
    144. int main()
    145. {
    146. MyVector<int> V1(5,2);
    147. cout<<"V1的第一个元素 = "<front()<
    148. cout<<"V1的最末一个元素 = "<back()<
    149. cout<<"V1的capacity = "<capacity()<
    150. cout<
    151. cout<<"********************************************************"<
    152. cout<
    153. V1.push_back(8);
    154. V1.push_back(5);
    155. V1.push_back(7);
    156. V1.push_back(6);
    157. cout<<"V1的第一个元素 = "<front()<
    158. cout<<"V1的最末一个元素 = "<back()<
    159. cout<<"V1的capacity = "<capacity()<
    160. cout<<"V1的size = "<get_size()<
    161. cout<
    162. cout<<"********************************************************"<
    163. cout<
    164. int *p = NULL;
    165. MyVector<int>::MyIterator q(p);
    166. cout<<"当前容器内的元素:";
    167. for(q = V1.begin();q != V1.end();q++){
    168. cout<< *q <<"\t";
    169. }
    170. cout<
    171. cout<
    172. cout<<"********************************************************"<
    173. cout<
    174. V1.pop_back();
    175. cout<<"V1的最末一个元素 = "<back()<
    176. V1.pop_back();
    177. cout<<"V1的最末一个元素 = "<back()<
    178. V1.pop_back();
    179. cout<<"V1的最末一个元素 = "<back()<
    180. cout<<"V1的size = "<get_size()<
    181. cout<
    182. cout<<"********************************************************"<
    183. cout<
    184. V1.clear();
    185. cout<<"V1的size = "<get_size()<
    186. return 0;
    187. }

    效果图:

    一、异常处理

    【1】异常概念

    C++中的异常指的是在程序运行过程中出现的问题,没有任何语法错误,存在逻辑问题

    【2】异常处理

    1. throw ----->抛出异常,抛出异常一定在异常发生之前
    2. try ····catch ----->捕获异常并进行异常处理

    总结:

    1. 抛出异常一定在发生异常之前
    2. try···catch中可以存放所有可能发生异常的代码,只要有一条语句抛出异常,try后面的语句都不会执行
    3. 异常可以只有数据类型,也可以及有数据类型也有值
    4. catch可以通过数据类型,获取到异常的结果并使用if进行判断,如果每种异常抛出的都是不同的数据类型,catch中就无需定义变量
    5. 如果同种数据类型的异常有多个值,要依次根据值来判断异常的情况
    6. throw抛出异常往往被调函数的位置,try···catch往往在主调函数内处理异常
    1. #include
    2. using namespace std;
    3. void fun(int a,int b)
    4. {
    5. //throw 数据类型(值)
    6. //数据类型:指定抛出异常的类型,便于接收
    7. //值:针对不同的异常情况,给出不同的值,处理异常时使用
    8. //在执行语句之前先对可能发生异常的位置进行判断
    9. if(b==0)
    10. {
    11. throw double(1);
    12. }
    13. if(b==3)
    14. {
    15. //函数内抛出了两个double类型的异常,分别返回不同的值
    16. throw int(2);
    17. }
    18. if(b==2)
    19. {
    20. throw double(2);
    21. }
    22. cout << a/b << endl;
    23. }
    24. //处理异常一般在主函数内
    25. //try···catch处理异常
    26. int main()
    27. {
    28. //tyr尝试接收异常,try内可以放多条语句,
    29. //有一条语句抛出异常后,后面都不会执行
    30. try
    31. {
    32. //try去接收所有可能的异常
    33. fun(4,2);
    34. fun(2,1);
    35. fun(3,3);
    36. }
    37. //由于函数中,只有一个double类型的异常,所以可以直接对异常的类型进行判断
    38. catch (double a) //如果double后面加变量名,变量会获取到异常的结果
    39. {
    40. if(a==1)
    41. cout << "除数为0" << endl;
    42. if(a==2)
    43. cout << "除数为2是一个测试" << endl;
    44. }
    45. catch (int)
    46. {
    47. cout << "除数为3是一个测试" << endl;
    48. }
    49. fun(3,1);
    50. cout << "1" << endl;
    51. }

    二、using的第三种用法

    1. #include
    2. //using namespace std;
    3. using std::string;
    4. class A
    5. {
    6. public:
    7. string name;
    8. };
    9. class B:public A
    10. {
    11. protected:
    12. using A::name;
    13. };
    14. namespace P {
    15. string n1;
    16. }
    17. //给命名空间重命名
    18. //namespace 新的名字 = 旧的名字
    19. //新名字和旧名字都能用
    20. namespace O = P;
    21. int main()
    22. {
    23. using std::cout;
    24. using std::endl;
    25. typedef int a; //后面可以直接使用a定义int类型的变量
    26. //C++11支持的
    27. using INT = int; //后面可以直接使用INT定义int类型的变量
    28. INT num1 = 100;
    29. cout << num1 << endl;
    30. P::n1 = "helo";
    31. O::n1 = "hi";
    32. cout << O::n1 << endl;
    33. return 0;
    34. }

    三、类型转换

    【1】隐式强转

    以及和C中一致的显式强转

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. float num1 = 2.3;
    6. int num2 = num1; //发生了隐式的强制类型转换
    7. //C中的显式强制类型转换
    8. double num3 = (double)num2;
    9. cout << num2 << endl;
    10. return 0;
    11. }

    【2】C++中支持的强制类型转换

    1. const_cast,取消常属性,取消常量指针的属性
    2. static_cast,和平时使用时发生强转用法一致,几乎支持所有类型间的强转
    3. dynamic_cast,发生在父子类指针间的转换,如果转换失败,会返回空地址
    4. reinterpret_cast,给类型重新赋值,不常用,不会检查数据类型匹配问题
    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. string name;
    6. public:
    7. virtual void show()
    8. {
    9. cout << name << endl;
    10. }
    11. };
    12. class B:public A
    13. {
    14. mutable int age;
    15. public:
    16. void fun()const
    17. {
    18. age = 90;
    19. }
    20. void show()
    21. {
    22. cout << &age << endl;
    23. }
    24. };
    25. int main()
    26. {
    27. //定义了一个常量num1
    28. const int num1 = 90;
    29. int *p; //定义了一个指针变量
    30. p = const_cast<int *>(&num1); //使用const_cast让指针指向const修饰的变量的地址
    31. *p = 12;
    32. cout << *p << endl;
    33. //mutable关键也可以取消常属性
    34. //static_cast适用于几乎所有的强制类型转换
    35. char var = 'a';
    36. int num2;
    37. //int num2 = (int)var;
    38. num2 = static_cast<int>(var);
    39. cout << num2 << endl;
    40. A* p1 = new B; //父类指针指向子类的空间
    41. A* p2 = new A; //父类指针指向父类的空间
    42. //B* p3 = static_cast(p2); p2指向父类的空间,但是static_cast可以强转成功
    43. B* p3 = dynamic_cast(p2);
    44. //使用了dynamic_cast,可以实现多态情况下,可以实现父子类指针的转换
    45. //如果父类指针没有指向子类的空间,返回值为0
    46. cout << "父类指针指向父类的空间" << p2 << endl;
    47. cout << "子类的指针" << p3 << endl;
    48. B* p4 = reinterpret_cast(p2);
    49. cout << "父类指针指向父类的空间" << p2 << endl;
    50. cout << "子类的指针" << p4 << endl;
    51. char *str = "hello";
    52. int a = reinterpret_cast<int>(str);
    53. cout << a << endl;
    54. //p3->show();
    55. return 0;
    56. }

    四、lambda表达式

    应用场合:

    想要使用匿名的、临时的函数,并且还需要获取外部变量时

    1. lambda(λ)表达式,是C++11支持的
    2. lambda表达式,用于实现轻量级的匿名函数
    3. 定义:[]()mutable->返回值{函数体}; --->结果一般使用auto接收
    1. [捕获列表](参数列表)mutable->返回值{函数体};
    2. 1、[=]:对所有变量按值捕获
    3. [&]:对所有变量按引用捕获
    4. [a,b]:对a和b按值捕获
    5. [&a,&b]:对a和b按引用捕获
    6. //[=,&a]:对除a外的变量值捕获,a按引用捕获
    7. //[&,a]:对除a外的变量按引用捕获,a按值捕获
    8. 2、参数列表:和普通函数的参数一致,就是传参数到函数中
    9. 3mutable可以写也可以不写:
    10. 如果不写mutable,在lambda表达式中不能修改按值捕获的变量的值,按引用捕获的不受影响
    11. 4、lambda实现的匿名函数的返回值
    12. 5、函数体就是匿名函数的实现
    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. int a = 90,b = 7,c,d,e;
    6. cout << "a=" << a << endl;
    7. cout << "b=" << b << endl;
    8. cout << "--------------------" << endl;
    9. //使用lambda表达式,实现主函数内变量值的交换
    10. //[=]:对所有变量按值捕获
    11. //[&]:对所有变量按引用捕获
    12. //[a,b]:对a和b按值捕获
    13. //[&a,&b]:对a和b按引用捕获
    14. //[=,&a]:对除a外的变量值捕获,a按引用捕获
    15. //[&,a]:对除a外的变量按引用捕获,a按值捕获
    16. //lambda表示式,使用auto类型获取
    17. auto fun = [&,a]()mutable->void{ int temp;
    18. temp = a;
    19. a = b;
    20. b = temp;};
    21. fun();
    22. //使用lambda实现求最大值
    23. auto max = [=]()->int{ if(a>b)
    24. return a;
    25. else
    26. return b; };
    27. cout << max() << endl;
    28. return 0;
    29. }

    五、STL标准模板库

    C++ Standard Template Library

    C++ 标准模板库(STL)

    C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 stacks(栈)等.

    C++ STL 提供给程序员以下三类数据结构的实现:

    • 顺序结构
      • C++ Vectors
      • C++ Lists
      • C++ Double-Ended Queues
    • 容器适配器
      • C++ Stacks
      • C++ Queues
      • C++ Priority Queues
    • 联合容器
      • C++ Bitsets
      • C++ Maps
      • C++ Multimaps
      • C++ Sets
      • C++ Multisets

    【1】Vector

    Vector的底层实现,就是线性表

    Vectors 包含着一系列连续存储的元素,其行为和数组类似。访问Vector中的任意元素或从末尾添加元素都可以在常量级时间复杂度内完成,而查找特定值的元素所处的位置或是在Vector中插入元素则是线性时间复杂度。

    需要手动导入头文件#include

    1. 1、求vetcor容器的大小:
    2. size_type capacity();
    3. capacity() 函数 返回当前vector在重新进行内存分配以前所能容纳的元素数量.
    4. 2、添加元素
    5. void push_back( const TYPE &val );
    6. push_back()添加值为val的元素到当前vector末尾
    7. 3、求容器的真实大小
    8. size_type size();
    9. size() 函数返回当前vector所容纳元素的数目
    10. 4、给容器中的元素赋值
    11. void assign( size_type num, const TYPE &val );
    12. 赋num个值为val的元素到vector中.这个函数将会清除掉为vector赋值以前的内容.
    13. 5、访问容器中的元素
    14. TYPE at( size_type loc );
    15. at() 函数 返回当前Vector指定位置loc的元素的引用. at() 函数 比 [] 运算符更加安全, 因为它不会让你去访问到Vector内越界的元素.
    16. 6、清空容器中的元素
    17. void clear();
    18. clear()函数删除当前vector中的所有元素.
    19. 7、判空函数
    20. bool empty();
    21. 如果当前vector没有容纳任何元素,则empty()函数返回true,否则返回false.例如,以下代码清空一个vector,并按照逆序显示所有的元素:
    22. 8、返回起始位置的引用
    23. TYPE front();
    24. front()函数返回当前vector起始元素的引用
    25. 9、返回最后一个位置的引用
    26. TYPE back();
    27. back() 函数返回当前vector最末一个元素的引用.
    28. 10、返回起始元素的迭代器
    29. iterator begin();
    30. begin()函数返回一个指向当前vector起始元素的迭代器.
    31. 11、返回末尾下一个位置的迭代器
    32. iterator end();
    33. end() 函数返回一个指向当前vector末尾元素的下一位置的迭代器.
    34. 注意,如果你要访问末尾元素,需要先将此迭代器自减1.
    35. 12、指定位置的插入,由于没有提供返回指定位置迭代器,需要在第一个元素的迭代器上运算
    36. iterator insert( iterator loc, const TYPE &val );
    37. 在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器,
    38. 13、移除最后一个元素
    39. void pop_back();
    40. pop_back()函数删除当前vector最末的一个元素,
    41. 14、构造函数
    42. vector( input_iterator start, input_iterator end );
    43. 迭代器(start)和迭代器(end) - 构造一个初始值为[start,end)区间元素的Vector(注:半开区间).

    【2】List

    list的底层实现是一个双向链表

    主要功能

    1. 1、头插
    2. void push_front( const TYPE &val );
    3. push_front()函数将val连接到链表的头部。
    4. 2、最大容量
    5. size_type max_size();
    6. max_size()函数返回链表能够储存的元素数目
    7. 3、元素个数
    8. size_type size();
    9. size()函数返回list中元素的数量。
    10. 4、排序
    11. void sort();
    12. 给链表中的元素排序,默认是升序
    13. 5、判空
    14. bool empty();
    15. empty()函数返回真(true)如果链表为空,否则返回假。

  • 相关阅读:
    你了解PMP考试新考纲的内容吗?
    Django笔记三十四之分页操作
    微服务概述
    RNA-seq——四、根据序列比对结果筛选差异基因
    WebView输入框软键盘遮挡问题(沉浸状态栏和adjustResize的冲突)
    氧化锌纳米线 Zinc oxide nanowires
    电脑可以模拟人脑吗
    ai实景直播矩阵式引流---技术开发搭建(剪辑、矩阵、直播)
    HTML5和CSS3二接口
    【cesium】3D Tileset 模型加载并与模型树关联
  • 原文地址:https://blog.csdn.net/weixin_54147737/article/details/132890268