一:动态内存对象分配
动态内存分配的语法: new 数据类型 (初始化参数);
如果内存申请成功,new运算便返回一个指向新分配内存首地址的类型的指针,可以通过这个指针对对象进行访问;如果失败,会抛出异常。
如建立的对象是基本类型对象,初始化过程就是赋值
如: int* point;
point=new int(2);
动态分配了用于存放int类型数据的内存空间,并将初值2存放在该空间,然后把首地址赋给指针point
两个细节:
1. int* point=new int;对象没有初始化
2.int* point=new int();把0对该对象初始化
区别:
new T 和 new T() 两种写法效果一不一样,得看 用户有没有定义了构造函数
删除对象语法
delete 指针名; 用new分配的内存,必须用delete加以释放,不然,系统无法回收,造成“内存泄露”
#include<iostream> using namespace std; class Point{ public: Point():x(0),y(0){//无形参构造函数 cout<<"Default Constructor called."<<endl; } Point(int x,int y):x(x),y(y){//有形参构造函数 cout<<"constructor called."<<endl; } ~Point(){ cout<<"Destructor called."<<endl;//析构函数 :用来完成对象被删除前的一些清理工作 } int getX() const { return x; } int getY() const{ return y; } void move(int newX,int newY){ x=newX; y=newY; } private: int x,y; }; int main(){ Point* ptr1=new Point;//动态创建对象没有给出参数列表,因此调用默认构造函数 delete ptr1;// 删除对象,自动调用析构函数 cout<<"setp two:"<<endl;//动态创建对象,并给出参数列表,因此调用有形参的构造函数 ptr1=new Point(1,2);//删除对象,自动调用析构函数 delete ptr1; return 0; }
二:动态一维数组的分配
语法:new 类型名[数组长度] 数组长度可以使任何能够得到的正整数的表达式
若:int* p=new int[10] (); 后面加了()括号,表明用0初始化数组
删除: delete[] 指针名;
#include<iostream> using namespace std; class Point{ public: Point():x(0),y(0){ cout<<"Default Constructor called."<<endl; } Point(int x,int y):x(x),y(y){ cout<<"constructor called."<<endl; } ~Point(){ cout<<"Destructor called."<<endl; } int getX() const { return x; } int getY() const{ return y; } void move(int newX,int newY){ x=newX; y=newY; } private: int x,y; }; int main(){ Point* ptr=new Point[2]; ptr[0].move(5,10); ptr[1].move(15,20); cout<<"Deleting..."<<endl; delete[] ptr; return 0; }
上面代码实例中利用动态内存分配操作实现了数组的动态创建,使得数组的个数可以根据运行时的需要而定。但是建立和删除数组的过程使得程序显得烦琐,更好的方法是将数组的建立和删除过程封装起来,形成一个动态数组类。
#include<iostream> #include<cassert> using namespace std; class Point{ public: Point():x(0),y(0){ cout<<"Default Constructor called."<<endl;//有形参构造函数 } Point(int x,int y):x(x),y(y){ cout<<"constructor called."<<endl;//析构函数 :用来完成对象被删除前的一些清理工作 } ~Point(){ cout<<"Destructor called."<<endl; } int getX() const { return x; } int getY() const{ return y; } void move(int newX,int newY){ x=newX; y=newY; } private: int x,y; }; //动态数组类 class ArrayOfPoints{ public: ArrayOfPoints(int size):size(size){ points=new Point[size]; } ~ArrayOfPoints(){ cout<<"Deleting..."<<endl; delete[] points; } Point &element(int index){ assert(index>=0&&index<size);//如果数组下标越界,程序终止 return points[index]; } private: Point* points;//指向动态数组的首地址 int size;//数组大小 }; int main(){ int count; cout<<"please enter the count of points:"; cin>>count; ArrayOfPoints points(count);//创建对象数组 points.element(0).move(5,0);//访问数组元素的成员 points.element(1).move(15,20);//访问数组元素的成员 return 0; }
三:动态创建多维数组
int main(){ float (*cp)[9][8]=new float[8][9][8]; for(int i=0;i<8;i++){ for(int j=0;j<9;j++) for(int k=0;k<8;k++) //以指针形式访问数组元素 *(*(*(cp+i)+j)+k)=static_cast<float>(i*100+j*100+k); } for(int i=0;i<8;i++){ for(int j=0;j<9;j++){ for(int k=0;k<8;k++) //将指针cp作为数组名使用,通过数组名和下标访问数组元素 cout<<cp[i][j][k]<<" "; cout<<endl; } cout<<endl; } return 0; }
四:用Vector创建数组对象
vector的作用:如果像上面那样将动态数组封装成一个类,来检测数组下标是否越界,
则检测不同类型的动态数组需创建其动态数组类,很烦琐。
于是C++标准库提供了被封装的动态数组---vector,
这种被封装的数组可以具有各种类型,使我们免去了很多重复性工作。
vector不是一个类,而是一个类模版
用vector定义动态数组的形式:
vector<元素类型>数组对象名<数组长度>;
@:用vector定义的数组对象的所有元素会被初始化,
如果基本数据类型,用0初始化。
如果是类类型,则会调用默认构造函数初始化,所有需要保证作为数组元素的类具有默认构造函数。
初值也可以自己指定: vector<元素类型>数组对象名(数组长度,元素初值)
用vector数组对象访问方式:
数组对象名[下标表达式]
#include<iostream> #include<vector> using namespace std; //计算数组arr中元素的平均值 double average(const vector<double>&arr){ double sum=0; for(unsigned i=0;i<arr.size();i++) sum+=arr[i]; return sum/arr.size(); } int main(){ unsigned n; cout<<"n=:"; cin>>n; vector<double>arr(n);//创建数组对象 cout<<"please input"<<n<<"real numbers:"<<endl; for(unsigned i=0;i<n;i++) cin>>arr[i]; cout<<"Average="<<average(arr)<<endl; return 0; }