当前位置:  编程技术>c/c++/嵌入式

C++动态数组类的封装实例

    来源: 互联网  发布时间:2014-10-27

    本文导语:  C++中的动态数组(Dynamic Array)是指动态分配的、可以根据需求动态增长占用内存的数组。为了实现一个动态数组类的封装,我们需要考虑几个问题:new/delete的使用、内存分配策略、类的四大函数(构造函数、拷贝构造函数、...

C++中的动态数组(Dynamic Array)是指动态分配的、可以根据需求动态增长占用内存的数组。为了实现一个动态数组类的封装,我们需要考虑几个问题:new/delete的使用、内存分配策略、类的四大函数(构造函数、拷贝构造函数、拷贝赋值运算符、析构函数)、运算符的重载。涉及到的知识点很多,对此本文只做简单的介绍。

一、内存分配策略

当用new为一个动态数组申请一块内存时,数组中的元素是连续存储的,例如 vector和string。当向一个动态数组添加元素时,如果没有空间容纳新元素,不可能简单地将新元素添加到内存中的其他位置——因为元素必须连续存储。所以必须重新分配一块更大的内存空间,将原来的元素从旧位置移动到新空间中,然后添加新元素,释放旧的内存空间。如果我们每添加一个新元素,就执行一次这样的内存分配和释放操作,效率将会慢到不行。

为了避免上述的代价,必须减少内存重新分配的次数。所以我们采取的策略是:在不得不分配新的内存空间时,分配比新的空间需求更大的内存空间(通常为2倍)。这样,在相当一段时间内,添加元素时就不用重新申请内存空间。注意,只有当迫不得已时才可以分配新的内存空间。

二、类的四大函数

一个C++类一般至少有四大函数,即构造函数、拷贝构造函数、拷贝赋值运算符、析构函数。如果类未自己定义上述函数,C++编译器将为其合成4个默认的版本。但是往往编译器合成的并不是我们所期望的,为此我们有必要自己定义它们。

1.构造函数

类的构造函数(constructor)用来初始化类对象的非static数据成员,无论何时只要类的对象被创建,就会执行构造函数。

class Foo { 
public: 
  Foo(); // 构造函数 
  Foo(string &s); 
  // ... 
}; 

构造函数的名字和类名相同,没有返回类型。类可以包含多个构造函数(重载),它们之间在参数数量或类型上需要有所区别。构造函数有一个初始化部分和一个函数体,成员的初始化是在函数体执行之前完成的。

2.拷贝构造函数

如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数(copy constructor)。

class Foo { 
public: 
  Foo(); 
  Foo(const Foo&); // 拷贝构造函数 
  // ... 
}; 

拷贝构造函数定义了如何用一个对象初始化另一个同类型的对象。拷贝初始化通常使用拷贝构造函数来完成。拷贝初始化发生在下列情况中:

使用等号(=)初始化一个变量
将一个对象作为实参传递给一个非引用类型的形参
从一个返回类型为非引用类型的函数返回一个对象
用花括号列表初始化一个数组中的元素

3.拷贝赋值运算符

类的拷贝赋值运算符(copy-assignment operator)是一个名为operator=的函数。类似于其他任何函数,它也有一个返回类型和一个参数列表。

class Foo { 
public: 
  Foo(); 
  Foo& operator=(const Foo&); // 赋值运算符 
  // ... 
}; 

拷贝赋值运算符定义了如何将一个对象赋值给另一个同类型的对象。赋值运算符是一个成员函数也是一个二元运算符,其左侧运算对象就绑定到隐式的this指针,右侧运算对象作为显式参数传递。注意:为了与内置类型的赋值保持一致,赋值运算符通常返回一个指向其左侧运算对象的引用。

4.析构函数

类的析构函数(destructor)用来释放类对象使用的资源并销毁类对象的非static数据成员,无论何时只要一个对象被销毁,就会自动执行析构函数。

class Foo { 
public: 
  ~Foo(); // 析构函数 
  // ... 
}; 

析构函数的名字由波浪号(~)加类名构成,也没有返回类型。由于析构函数不接受参数,因此它不能被重载。析构函数有一个函数体和一个析构部分,销毁一个对象时,首先执行析构函数体,然后按初始化顺序的逆序销毁成员。

三、运算符的重载

重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成。和其他函数一样,重载的运算符也包含返回类型、参数列表、函数体,比如拷贝赋值运算符。

当我们定义重载的运算符时,必须首先决定是将其声明为类的成员函数还是声明为一个普通的非成员函数。有些运算符必须作为成员,而另一些运算符作为普通函数比作为成员更好:

赋值(=)、下标([ ])、调用(( ))和成员访问箭头(->)运算符必须是成员。
复合赋值运算符一般来说应该是成员,但并非必须,这一点与赋值运算符略有不同。
改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减、解引用运算符,通常应该是成员。
具有对称性的运算符可能转换任意一端的运算对象,例如算术、相等性、关系和位运算符等,因此它们通常应该是普通的非成员函数。
当然,除了赋值运算符之外,我们还需要为动态数组定义下标运算符operator []。下标运算符必须是成员函数。为了让下标可以出现在赋值运算符的任意一端,下标运算符函数通常返回所访问元素的引用。

四、动态数组类的封装

下面给出了动态数组DArray类的接口:

class DArray 
{ 
private: 
  double *m_Data; // 存放数组的动态内存指针 
  int m_Size;   // 数组的元素个数 
  int m_Max;    // 预留给动态数组的内存大小 
private: 
  void Init();   // 初始化 
  void Free();   // 释放动态内存 
  inline bool InvalidateIndex(int nIndex); // 判断下标的合法性 
public: 
  DArray();    // 默认构造函数 
  DArray(int nSize, double dValue = 0); // 构造函数,设置数组大小,默认值为dValue 
  DArray(const DArray& arr); // 拷贝构造函数 
  DArray& operator=(const DArray& arr); // 拷贝赋值运算符 
  ~DArray();    // 析构函数 
 
  void Print();  // 输出显式所有数组元素的值 
  int GetSize();  // 获取数组的大小(元素个数) 
  void SetSize(int nSize); // 重新设置数组的大小,若nSize小于原大小,截断;否则,新元素置0 
  double GetAt(int nIndex); // 获取指定位置元素 
  void SetAt(int nIndex,double dValue); // 重置指定元素的值 
  void PushBack(double dValue); // 追加一个新元素到数组末尾 
  void DeleteAt(int nIndex);   // 删除指定位置地元素 
  void InsertAt(int nIndex, double dValue); // 插入一个新的元素到数组中 
  double operator[](int nIndex) const;   // 重载下标运算符[] 
}; 

下面是实现方法:

void DArray::Init() 
{ 
  m_Size = 0;  // 默认情况下数组不包含元素 
  m_Max = 1; 
  m_Data = new double[m_Max]; 
} 
 
void DArray::Free() 
{ 
  delete [] m_Data; 
} 
 
bool DArray::InvalidateIndex(int nIndex) 
{ 
  if(nIndex>=0 && nIndex

    
 
 

您可能感兴趣的文章:

  • C++动态编译工具 ccbuild
  • 在linux下(c++),如何动态调用 动态库(.so)? 为什么我编译报错:undefined reference to "dlopen"
  • c程序调dlopen C++的动态库的问题,急!
  • linux下c++对长度不定的字符串要进行预先动态分配内存需要怎么做?
  • 请问:linux 下 如何在一个动态库(so文件)中到处 C++类?感激不尽!
  • C++实现动态分配const对象实例
  • 用C++写动态库问题
  • C++中关于[]静态数组和new分配的动态数组的区别分析
  • linux下C++动态malloc申请内存出现问题,高人指点一下,在线
  • c++动态内存空间示例(自定义空间类型大小和空间长度)
  • AIX中用xlc是否能链接C++的动态库,需要添加什么参数?
  • 深入理解C++的动态绑定与静态绑定的应用详解
  • 想用C++在Linux下实现动态链接,以下是我的代码请帮忙参考,急!
  • C++的静态联编和动态联编详解
  • 用c++写动态库,其他模块怎么调用????分不够还可以加
  • LINUX环境C++动态链接库如何才能被C应用程序调用?急急!
  • 用C++ 类的形式设计 Linux动态链接库(.so 文件),出现了那个问题,在线等
  • C++对象的动态建立与释放详解
  • 用C++ 类的形式设计 Linux动态链接库(.so 文件),出现了那个问题,问问大家
  • 在Visual Studio中用C++语言创建DLL动态链接库图文教程
  • 动态数组的用法?
  • 请问再java中怎样定义动态数组?
  • 数组能不能动态改变大小?
  • java中如何实现二维(多维)动态数组.谢谢
  • java能否动态开辟string数组?
  • C语言构建动态数组完整实例
  • 动态数组的运用
  • 如何为数组动态开辟内存???
  • 动态分配数组的疑问。
  • 能不能给指针数组动态分配内存
  • 请高手帮忙:如何动态声明一维数组?
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • linux如何将rsync源码封装成动态库留出接口供外部函数调用?
  • Linux中,如何用动态共享库(.so)来封装某个纯数据文件
  • Linux下指定运行时加载动态库路径及shell下执行程序默认路径
  • 可执行程序加载动态库 和 动态库加载动态库 的动态库初始化的问题
  • Linux下c函数dlopen实现加载动态库so文件代码举例
  • 关于动态菜单项,注意,不是动态菜单(一定给分) iis7站长之家
  • linux动态链接库里全局变量和静态变量会导致动态库不可重入吗?
  • linux能否成为动态域名解析客户端的动态域名解析服务器?
  • 关于动态菜单项,注意,不是动态菜单(一定给分)
  • Linux下,怎么确定动态库的绝对位置(动态库里面确定)?
  • 为什么动态生成的图片,JSP不能动态的获得
  • 请问:能不能动态的运行时生成对象(动态定义对象), 要涉及到哪些技术, 反射,序列化...??
  • 动态加载动态库问题--在线等
  • C#实现动态显示及动态移除图片方法
  • 静态库,动态库,静态链接和动态链接
  • 程序发布的问题(动态连接库的问题)
  • JSP动态缓存 JimStoneCache
  • 怎么调试unix动态库.
  • 如何调用动态
  • 动态编译与静态编译驱动程式疑问?
  • 关于动态库的问题,谢谢!
  • linux动态路由问题
  • 内核与动态(共享)库




  • 特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3