01 实现自定义的可变长数组类型

假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的。

int main()
{MyArray a;  // 初始化的数组是空的for(int i = 0; i < 5; ++i)a.push_back(i); // push_back是成员函数MyArray a2,a3;a2 = a; // 重载赋值运算符函数// 由于上一句a2 = a语句,所以a.length()实际上就是a2.length()for(int i = 0; i < a.length(); ++i) cout << a2[i] << " ";a2 = a3; // a2是空的数组for(int i = 0; i < a2.length(); ++i) // a2.length()返回0cout << a2[i] << " ";cout << endl;a[3] = 100;    // 重载[]运算符函数MyArray a4(a); // 重载复制构造函数for(int i = 0; i < a4.length(); ++i)cout << a4[i] << " ";return 0;
}

输出结果:

0 1 2 3 4
0 1 2 100 4

要实现的方式,要做哪些事情呢?我先列一下:

  • 要用动态分配的内存来存放数组元素,需要一个指针成员变量
  • 重载赋值=运算符
  • 重载[]运算符
  • 重载复制构造函数
  • 实现push_back和length()函数

02 MyArray类的实现步骤

要实现一个可变长数组类的,基本需要实现下面的7个函数:

class MyArray // 可变长数组类
{public:// 1. 构造函数,s代表数组元素的个数MyArray(int s = 0);// 2. 复制构造函数MyArray(MyArray &a);// 3. 析构函数~MyArray();// 4. 重载赋值=运算符函数,用于数组对象间的赋值MyArray & operator=(const MyArray & a);// 5. 重载[]运算符函数,用于获取数组下标对于的值int & operator[](int i);// 6. 加入一个元素到数组的末尾void push_back(int v);// 7. 获取数组的长度int length();private:int  m_size; // 数组元素的个数int* m_ptr;  // 指向动态分配的数组
};

1. 构造函数

构造函数的目的就是初始化一个数组,代码如下:

// 构造函数
MyArray::MyArray(int s = 0):m_size(s)
{// 当初始化长度为0的数组时,数组指针就是空的if(s == 0)m_ptr = NULL;// 当初始化长度不为0时,则申请对应大小的空间elsem_ptr = new int[s];
}

2. 复制构造函数

复制构造函数目的就是产生一个与入参对象一样的对象,但是由于MyArray类是有指针成员变量的,所以我们必须才用深拷贝的方式来实现复制构造函数,如果使用默认的复制构造函数,则会导致两个对象的指针成员变量指向的地址是同一个,这是非常危险的。

// 复制构造函数
MyArray::MyArray(const MyArray &a)
{// 如果入参的数组对象的指针地址为空时,则也初始化一个空的数组if(a.m_ptr == NULL){m_ptr = NULL;m_size = 0;}// 如果入参的数组对象有数据时,则申请一个新的地址,最后来复制入参对象数组对象的数据和大小。else{m_ptr = new int[a.m_size];memcpy(m_ptr, a.m_ptr, sizeof(int)*a.m_size);m_size = a.m_size;}
}

3. 析构函数

析构函数的目的就是释放数组的资源

// 析构函数
MyArray::~MyArray()
{// 如果指针地址不为空时,则释放资源if(m_ptr)delete [] m_ptr;
}

4. 重载赋值=运算符函数

重载赋值=运算符函数目的就使=号左边对象里存放的数组,大小和内容都和右边的对象一样

// 重载赋值=运算符函数
MyArray & MyArray::operator=(const MyArray & a)
{if(m_ptr == a.m_ptr) // 防止a=a这样的赋值导致出错return *this; if(a.m_ptr == NULL) // 如果a里面的数组是空的{if(m_ptr)delete [] m_ptr; // 释放旧数组的资源m_ptr = NULL;m_size = 0;return *this;}if(m_size < a.m_size) // 如果原有空间足够大,就不用分配新的空间{if(m_ptr)delete [] m_ptr; // 释放旧数组的资源m_ptr = new int[a.m_size]; // 申请新的内存地址}memcpy(m_ptr, a.m_ptr, sizeof(int)*a.m_size);m_size = a.m_size;return *this;
}

5. 重载[]运算符函数

重载[]运算符函数目的就是能通过[]运算符来获取对应下标的数组值

// 重载[]运算符函数
int & MyArray::operator[](int i)
{return m_ptr[i]; // 返回对应下标的数组值
}

6. 加入元素到数组末尾的函数

push_back函数的目的就是把一个新的元素,加入到数组的末尾

// 在数组尾部添加一个元素
void MyArray::push_back(int v)
{if(m_ptr) // 如果数组不为空{int *tmpPtr = new int[m_size + 1]; // 重新分配空间memcpy(tmpPtr, m_ptr, sizeof(int)*m_size); // 拷贝原数组内容delect [] m_ptr;m_ptr = tmpPtr;}else // 如果数组本来就是空的{m_ptr = new int[1];   }m_ptr[m_size++] = v; //加入新的数组元素
}

7. 获取数组长度的函数

length()函数就比较简单了,直接返回成员变量m_size,就是数组的长度了

// 获取数组长度的函数
int MyArray:;length()
{return m_size;
}

03 小结

可变长数组类型实现的整体代码,如下:

class MyArray
{public:// 1. 构造函数,s代表数组元素的个数MyArray(int s = 0):m_size(s){if(s == 0)m_ptr = NULL;elsem_ptr = new int[s];}// 2. 复制构造函数MyArray(const MyArray &a){if(a.m_ptr == NULL){m_ptr = NULL;m_size = 0;}else{m_ptr = new int[a.m_size];memcpy(m_ptr, a.m_ptr, sizeof(int)*a.m_size); // 拷贝原数组内容m_size = a.m_size;}}// 3. 拷贝构造函数~MyArray(){if(m_ptr)delete [] m_ptr;}// 4. 重载赋值=运算符函数MyArray & operator=(const MyArray & a){if(m_ptr == a.m_ptr)return *this;if(a.m_ptr == NULL){if(m_ptr)delete [] m_ptr;m_ptr = NULL;m_size = 0;return *this;}if(m_size < a.m_size){if(m_ptr)delete [] m_ptr;m_ptr = new int[a.m_size];}memcpy(m_ptr, a.m_ptr, sizeof(int)*a.m_size); // 拷贝原数组内容m_size = a.m_size;return *this;}// 5. 重载[]运算符函数int & operator[](int i){return m_ptr[i];}// 6. 在数组的末尾加入一个新的元素void push_back(int v){if(m_ptr) // 如果数组不为空{int *tmpPtr = new int[m_size + 1]; // 重新分配空间memcpy(tmpPtr, m_ptr, sizeof(int)*m_size); // 拷贝原数组内容delete [] m_ptr;m_ptr = tmpPtr;}else // 如果数组本来就是空的{m_ptr = new int[1];   }m_ptr[m_size++] = v; //加入新的数组元素}// 7. 获取数组的长度int length(){return m_size;}private:int  m_size; // 数组元素的个数int* m_ptr;  // 指向动态分配的数组
};

实际上本次的可变长的数组类还缺少一下函数,比如:删除某个元素的函数、清空数组的函数等等,这些可以留给大家思考。

还有就是 push_back 函数还有优化的空间,当前的 push_back 函数每加入一个元素都会重新分配新的内存,这是会增大开销的,那么优化的思路:
提前分配好一个 n 大小的空间,当数组大小不够的时候,则才继续重新分配 2n 大小的空间,以此类推。

C++ 手把手教你实现可变长的数组相关推荐

  1. C/C++编程知识分享:C++ 手把手教你实现可变长的数组

    01 实现自定义的可变长数组类型 假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的. 输出结果: 要实现的方式,要做哪些事情呢?我 ...

  2. delphi 获取数组长度_C++可变长的数组,老司机手把手教你实现!

    01 实现自定义的可变长数组类型 假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的. int main(){ MyArray a; ...

  3. socket 长链接linux,手把手教你写 Socket 长连接

    原标题:手把手教你写 Socket 长连接 8点43分打卡 就是真爱 本文转载自公众号 玉刚说,由玉刚说写作平台[1]提供写作赞助 原作者:水晶虾饺[2] 版权声明:本文版权归微信公众号玉刚说所有,未 ...

  4. 手把手教你写 Socket 长连接

    本文由玉刚说写作平台[1]提供写作赞助 原作者:水晶虾饺[2] 版权声明:本文版权归微信公众号 玉刚说 所有,未经许可,不得以任何形式转载 本篇我们先简单了解一下 TCP/IP,然后通过实现一个 ec ...

  5. 怎样在数组末尾添加数据_如何利用C++实现可变长的数组?

    应该执行什么功能? 假设我们要实现一个将自动扩展的数组类,是否需要实现函数?让我们从下面主要功能使用的功能开始,看看我们需要实现哪些功能. 输出结果: 0 1 2 3 4 0 1 2 100 4 您需 ...

  6. C++可变长数组vector的使用

    最近在刷算法,C++里自带的一些容器.函数真是非常简便了. 下面介绍一种可变长的数组,和数组类似,但比数组更强大更方便~~~ 可边长数组: vector<int> v(N,i); 头文件: ...

  7. 高效 保活长连接:手把手教你实现 自适应的心跳保活机制

    前言 当实现具备实时性需求时,我们一般会选择长连接的通信方式 而在实现长连接方式时,存在很多性能问题,如 长连接保活 今天,我将 手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接 目录 1. ...

  8. 其他行 展开 收起_长居清迈的家庭,去台湾依旧可以自由行?手把手教你网上申请赴台证...

    台北@西门町 8月份有朋友告诉我们,在大陆叫停台湾自由行之后,持泰国长居签证的大陆居民,依旧可以向曼谷的驻泰国台北经济文化办事处申请台湾自由行,而且全程只需要在网上提交资料+缴费+下载许可证,高兴坏了 ...

  9. android 心跳 简书,如何高效维持网络长连接:手把手教你实现 自适应的心跳保活机制...

    前言 当实现具备实时性需求时,我们一般会选择长连接的通信方式 而在实现长连接方式时,存在很多性能问题,如 长连接保活 今天,我将 手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接 目录 示意 ...

最新文章

  1. 中国大学的现实:层次越低,上课越多,学生读书越少
  2. 沈向洋官宣离职微软!他是微软级别最高的中国人、微软AI领导者,21年前参与创办MSRA...
  3. 零基础可以学python吗-python零基础能学吗
  4. php 7.1/7.3使用 json_encode 函数造成浮点类型数据出现精度问题
  5. Redis源码剖析(二)io多路复用函数及事件驱动流程
  6. celery学习笔记:celery安装,并运行第一个应用
  7. 家乐福举报山姆涉嫌“二选一”背后 会员店需要的不是模仿能力
  8. python如何调用阿里云接口_Python调用阿里云API接口实现自定义功能【二】——DescribeInstance窗口操作...
  9. 火狐与IE兼容性总结(一)
  10. 【信息技术】【2014】【含源码】PGP加密软件
  11. 夜神模拟器安装frida-server图文详解
  12. python时间序列进行线性插值_精解Python实现线性插值法——一看就会
  13. 科学计算机算方差与期望,期望、方差、协方差及相关系数的基本运算
  14. 阅读心得:JDE:Towards Real-Time Multi-Object Tracking
  15. 干货 领导力21法则思考
  16. python re span_python—模块-re正则表达式
  17. Mac sublime3 在localhsot 上打开项目文件
  18. 数据库课程设计----学生信息与选课、成绩评价管理系统
  19. 苹果电脑查看已经连上的WiFi密码(亲测可用)
  20. 51单片机入门——Proteus 8 Professional的使用

热门文章

  1. Loose Ends
  2. 修复电脑蓝屏(电脑自动修复失败)
  3. python3--最新google_trans_new超时报错JSONDecodeError解决
  4. 东北计算机考研难度性价比,全国211院校考研难度分析,建议收藏!(详细版)...
  5. 微信支付上线遇到的nss问题 (openjdk引起的祸)
  6. https://nbicddnbp.pxvqgzr.com/f/Y315nOiv1 fu指喲 考貝该段,点開块手
  7. 网络系统管理Debian模块||RouterSrv的openvpn配置详解
  8. Matrix矩阵的基础案例与分析
  9. MATLAB信号处理——分解信号,双谱重构
  10. 【劳动最光荣】TcaplusDB祝大家劳动节快乐