C++ 不支持数组的抽象 abstraction 也不支持对整个数组的操作我们有时会希望对整个数组进行操作例如把一个数组赋值给另外一个数组对两个数组进行相等比较或者想知道数组的大小 size 例如给出两个数组我们不能用赋值操作符把一个数组拷贝到另一个中去。
int array0[ 10 ], array1[ 10 ];
array0 = array1; // error
数组类型本身没有自我意识它不知道自己的长度我们必须另外记录数组本身的这些信息。
数组和指针的关系:
int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 };
ia; 意味着什么。数组标识符代表数组中第一个元素的地址它的类型是数组元素类型的指针。
ia; 等价 &ia[0];
*(ia+1); 等价 ia[1];
对象创建
* 第一种是直接定义类的实例——对象:
CGoods Car;
这个定义创建了CGoods类的一个对象Car,同时为它分配了属于它自己的存储块,用来存放数据和对这些数据实施操作的成员函数(代码)。与变量定义一样,一个对象只在定义它的域中有效。
* 第二种是采用动态创建类的对象的方法。
动态内存分配(Dynamic Memory Allocation)可以解决诸如数组大开小用等静态编译不能解决的问题。
C/C++定义了4个内存区间:1)、代码区,2)、全局变量与静态变量区,3)、局部变量区即栈区,4)、动态存储区,即堆(heap)区或*存储区(free store)。
静态分配和动态分配:
通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配。
有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据要求进行内存分配,这种方法称为动态存储分配。
所有动态存储分配都在堆区中进行。当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。
动态分配格式:指针变量名=new 类型名(初始化式);
delete 指针名;
eg:
int *pi=new int(0);
delete pi; //注意,释放了pi指向的目标内存空间,但是pi指针本身并没有撤销,该指针占的内存空间并没有释放。
说明:
*new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。
* 一般定义变量和对象时要用标识符命名,称命名对象,而动态的称无名对象(请注意与栈区中的临时对象的区别,两者完全不同:生命期不同,操作方法不同,临时变量对程序员是透明的)。
* 堆区不会在分配时做自动初始化(包括清零),必须用初始化式(initializer)来显式初始化。
* new表达式的操作序列如下:从堆区分配对象,然后用括号中的值初始化该对象。
基于对象设计
实现数组抽象,
1. 数组类的实现中有内置的自我意识首先它知道自己的大小。
2. 数组类支持数组之间的赋值以及两个数组之间的相等和不相等的比较操作。
3. 数组类应该支持对其所含的值进行下列查询操作数组中最小值是什么最大值是什么某个特殊的值是否在数组中如果存在它占的第一个位置的索引是什么。
4. 数组类支持自排序为了便于讨论假定存在一群用户他们认为数组支持排序的功能很重要而另外一些人对此却不以为然除了支持数组操作还必须支持数组本身的机制包括。
5. 能够指定长度以此来创建数组这个值无需在编译时刻知道。
6. 能够用一组值初始化数组。
7. 能够通过一个索引来访问数组中的单个元素为便于讨论假设用户强烈要求用数组下标操作符来实现这项功能。
8. 能够截获并指出错误的索引值假设我们认为这很有必要所以没有询问用户的想法我们认为这是一个设计良好的数组所必须实现的我们与潜在用户的讨论已经引起了极大的热。
IntArray.h
class IntArray { private : int _size; //数组大小 int *p; //数组指针 public: IntArray(int array_size); IntArray(int *array,int array_size); IntArray(IntArray &arr);//拷贝构造函数 ~IntArray(); void sort(); //排序 int find(int value);//查找 int max();//最大元素 int min();//最小元素 int size();//数组大小 void display(); };
IntArray.cpp
#include <iostream> //io流文件引入 #include "IntArray.h" using namespace std; /************************************************************************/ /* 构造方法 默认数组元素初始化为0 */ /************************************************************************/ IntArray::IntArray(int array_size) { _size = array_size; p = new int[array_size]; for (int i = 0; i<array_size; i++) { p[i] = 0; } } /************************************************************************/ /* 构造方法 用一个数组初始化另外一个数组 */ /************************************************************************/ IntArray::IntArray(int *array,int array_size) { _size = array_size; p = new int[array_size]; for (int i = 0; i<array_size; i++) { p[i] = array[i]; } } /************************************************************************/ /* 计算数组最大值 */ /************************************************************************/ int IntArray::max() { int max = -1; for (int i = 0; i< _size; i++) { if (p[i] > max) { max = p[i]; } } return max; } /************************************************************************/ /* 计算数组最小值 */ /************************************************************************/ int IntArray::min() { int min = 10000; for (int i = 0; i<_size; i++) { if(p[i] < min) { min = p[i]; } } return min; } /************************************************************************/ /* 查找指定元素,返回在数组中的位置 */ /************************************************************************/ int IntArray::find(int value) { int index = -1; for (int i = 0; i<_size; i++) { if(p[i] == value) { index = i; } } return index; } /************************************************************************/ /* 返回数组大小 */ /************************************************************************/ int IntArray::size() { return _size; } /************************************************************************/ /* 显示数组元素中的值 */ /************************************************************************/ void IntArray::display() { for (int i = 0; i<_size; i++) { cout<<p[i]<<" "; } cout<<endl; } /************************************************************************/ /* 对数组排序,升序 or 降序 */ /************************************************************************/ void IntArray::sort() { } /************************************************************************/ /* 析构函数,释放内存空间 */ /************************************************************************/ IntArray::~IntArray() { delete p; } /************************************************************************/ /* 主调函数 */ /************************************************************************/ int main(void) { int intA[] = {10,2,4,6,7,98,32,4}; IntArray intArr(intA,8); cout<<"size:"<< intArr.size() <<endl; cout<<"max:"<<intArr.max() <<endl; cout<<"min:"<< intArr.min() <<endl; cout<<"find:"<< intArr.find(98) <<endl; intArr.display(); intArr.~IntArray(); }泛型设计(generic programming)
IntArray 类为预定义的整型数组类型提供了一个有用的替代类型如果用户希望使用一个 double 或 string 类型的数组
关键字 template 引入模板参数由一对尖括号 < > 括起来
template < class elemType > class Array { public: Array( int size ); Array( elemType *array, int array_size ); virtual elemType min() ; virtual elemType max() ; private: int _size; elemType *ia; };以后当我们实例化 instantiate 一个特定类型的实例时如 int double 或string 类型的 Array 数组就可以在程序中直接使用这三个实例.
调用:
const int array_size = 4;
//elemType 变成了int
Array<int> ia(array_size);
//elemType 变成了double
Array<double> da(array_size);
//elemType 变成了char
Array<char> ca(array_size);
类模板的成员函数会怎么样呢不是所有的成员函数都能自动地随类模板的实例化而被实例化只有真正被程序使用到的成员函数才会被实例化这一般发生在程序生成过程中的一个独立阶段。