用
CShape* pShape;
pShape = new CLine();
pShape->draw();
和
CLine a;
a.draw();
这种方式声明对象有河区别??
问题补充:
什么时候用CLine a;这种方式
什么时候用pShape = new CLine(); 这种方式
声明一对象
其中你这两个例子执行结果是一致的!但为什么要用多态?
最主要的使用是为不同派生使用同样的驱动,即一个单一接口或变量。
如
void AdvancedDraw()函数可以为不同派生内做高级绘图操作,这些派生类有,CLine, CCircle, CAngle等。则这样的函数为:
void AdvancedDraw(CLine &c);
void AdvancedDraw(CCircle &c);
vodi AdvancedDraw(Cangle &c);
以后每增加一个派生类需要增加一个处理函数,但是,如果利用多态,则只要一个函数
void AdvancdDraw(CShape &c)
{
// others
c.draw();
}
这样会自动根据对象类型调用不同派生类的draw();
还有如
一个模块根据用户输入决定绘制操作,不利用多态则为:
CLine a;
CCircle b;
Cangle c;
swtch(sel)
{
case 1: a.draw(); break;
case 2: b.draw(); break;
case 3: c.draw(); break;
}
以后增加新派生类,在这个模块中还需要增加变量,诸如d, e, f等。但利用多态则,只要一个变量来处理。如
CShape *a;
swtch(sel)
{
case 1: a = new CLine; break;
case 2: a = new CCircle; break;
case 3: a = new Cangle; break;
}
a->draw();
这样代码需要修改的地方很少,减少出错的概率。
三种形式的new表达式
<1> 单个对象的动态分配
<2> 数组的动态分配
<3> 定位new表达式
------------------------------------------------------------------
<1>
#define TR(S) cout << #S" : " << S << endl
int *pi = new int(11); // initializer
TR(*pi);
int i = 22;
int *q = new int; //assign
*q = i;
TR(*q);
* 因为new表达式是从堆上申请内存,但堆上空闲储存区是有限的,但空闲储存区内存耗尽时,导致new表达式失败,抛出bad_alloc异常
* 常见new错误 <1> delete表达式失败(内存泄漏 memory leak) <2>对同以内存用2次delete <3>对象被释放后继续读写该对象
---------------------------------------------
auto_ptr (自动管理用new表达式动态分配的内存)
auto_ptr<int> pi(new int(11));
cout << *pi << endl;
pi的作用域跟普通变量的作用域一样的,在pi的生命期结束时, 被释放
{
auto_ptr<int> pi(new int(11));
}
cout << *pi << endl; // error C2065: 'pi' : undeclared identifier
------------------------------------------------------------------------
auto_ptr<int> p1(new int(11));
auto_ptr<int> p2(new int(22));
cout << *p1 << endl;
cout << *p2 << endl;
p1 = p2;
cout << *p1 << endl;
//cout << *p2 << endl; // error 这样p2被重置为0
if (p2.get() == 0) //
cout << "p2 is alive" << endl;
p2.reset(new int(33)); // 只能这样重置p2
cout << *p2 << endl;
----------------------------------------------------------------------
auto_ptr<string> str1(new string("aaaaa"));
str1.reset(new string("bbbbbbbbb"));
cout << *str1 << endl;
str1->assign("ccccc"); //这样更有效...
cout << *str1 << endl;
需要包含头文件string 和memory 刚才一时情急忘了加#inlcude<string> 然后居然把输出写成cout << str1 << endl;没有解引用...呵呵...- -!
* 用auto_ptr对象并不比直接使用指针代价高,大多操作都是inline的
*auto指针的是用指针的所有权方式,当把一个指针赋值给另一个指针的时候,后者拥有所有权,前者不再指向原来的对象,被赋值为0.
---------------------------------------------------------------------------
int *p = 0;
if ( !p )
cout << "p is non-initialize" << endl;
auto_ptr<int> p2; // 从这里也能看出跟普通指针的不同, auto_ptr自动将对象初始化为0
if (!p2.get())
cout << "p2 is non-initialize" << endl;
*使用普通指针是可以用是否为0,而auto_ptr不可以,auto_ptr用get()返回对象内部的底层指针(用reset()来重置一个底层指针),
----------------------------------------------------------
* 不能用一个指向"内存不是用new分配的"指针来初始化或者赋值auto_ptr指针
* 不能让两个auto_ptr对象拥有空闲存储区内同一对象的所有权()
2>数组的动态分配
int *pi = new int[11]; // 分配有11个元素的动态数组
int (*pia)[11] = new int [22][11]; //分配一个含有 22 * 11 个元素的二维数组
* 动态分配的数组不能给出初始化值,一般在 for 循环中一个一个的初始化
eg: for(int i = 0; i < 11; i++)
pi[i] = 0;
* 动态数组的第一维不必是常量值, 这样就不必在编译时刻就知道维数,我们可以根据需要分配大小合适的内存单元
* 释放动态数组: delete [ ] pi; 如果不小心忘记了空括号,编译器不会捕捉到这个错误, 务必要小心
* 一般为了避免动态分配数组带来的内存管理的问题, 我们使用c++ 的 标准库vector, list or string 会自动管理内存的容器类型
---------------------
常量对象的动态分配
const int *pic = new const int(1024);
* const 对象必须被初始化, 否则会编译错误,(因此我们也不能创建const数组,因为const数组不能被初始化,除了类数组)
* 用new表达式返回的值作为初始值的指针必须是一个指向const类型的指针. eg: const int
* 它的生命期同样也用delete表达式来结束 eg: delete pic;
=============================================================
<3>定位new表达式(placement new expression)
形式: new (place_address) type-specifier
头文件: #include <new>
place_adress必须是指针
eg:
int *buf = new int[2];
int *pb = new (buf) int;
*pb = 11;
cout << *pb << endl; // 11
cout << *buf << endl; // 11
cout << pb << endl; // 同样pb跟buf的所指向的地址也是相同的
cout << buf << endl; //
int *pp = new (buf + 1) int;
*pp = 22;
* 因为定位符并不分配内存,所以我们并没有与定位符相匹配的delete表达式, 对此我们需要删除的是分配内存的指针,在上面的例子中我们 delete [] buf;
new和delete运算符用于动态分配和撤销内存的运算符
new用法:
1. 开辟单变量地址空间
1)new int; //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.
2)int *a = new int(5) 作用同上,但是同时将整数赋值为5
2. 开辟数组空间
一维: int *a = new int[100];开辟一个大小为100的整型数组空间
二维: int *a = new int[5][6]
三维及其以上:依此类推.
一般用法: new 类型 [初值]
delete用法:
1. int *a = new int;
delete a; //释放单个int的空间
2.int *a = new int[5];
delete [] a; //释放int数组空间
要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问.
用new和delete可以动态开辟,撤销地址空间.在编程序时,若用完一个变量(一般是暂时存储的数组),下次需要再用,但却又想省去重新初始化的功夫,可以在每次开始使用时开辟一个空间,在用完后撤销它
int *a = new int[5][6]
vc里行不通
应该是
int(*a)[6]=new int[5][6]
c++中new的几种用法
在释放时有区别。你用new申请的堆内存,你有释放它的义务和责任,你必须用delete释放它,否则会造成内存泄漏,即memory leak, 对于一个对象而言,释放它的方式取决于你的构造函数,是否用到new申请内存。但是例2的指针是一定要用delete释放的。
c++中,new的用法很灵活,这里进行了简单的总结:
1. new() 分配这种类型的一个大小的内存空间,并以括号中的值来初始化这个变量;
2. new[] 分配这种类型的n个大小的内存空间,并用默认构造函数来初始化这些变量;
#include<iostream>
#include<cstring>
using namespace std;
int main(){
//char* p=new char("Hello");
//error分配一个char(1字节)的空间,
//用"Hello"来初始化,这明显不对
char* p=new char[6];
//p="Hello";
//不能将字符串直接赋值给该字符指针p,原因是:
//指针p指向的是字符串的第一个字符,只能用下面的
//strcpy
strcpy(p,"Hello");
cout<<*p<<endl; //只是输出p指向的字符串的第一个字符!
cout<<p<<endl; //输出p指向的字符串!
delete[] p;
return 0;}
输出结果:
H
Hello
3. 当使用new运算符定义一个多维数组变量或数组对象时,它产生一个指向数组第一个元素的指针,返回的类型保持了除最左边维数外的所有维数。例如:
int *p1 = new int[10];
返回的是一个指向int的指针int*
int (*p2)[10] = new int[2][10];
new了一个二维数组, 去掉最左边那一维[2], 剩下int[10], 所以返回的是一个指向int[10]这种一维数组的指针int (*)[10].
int (*p3)[2][10] = new int[5][2][10]; new了一个三维数组, 去掉最左边那一维[5], 还有int[2][10], 所以返回的是一个指向二维数组int[2][10]这种类型的指针int (*)[2][10].
#include<iostream>
#include <typeinfo>
using namespace std;
int main() {
int *a = new int[34];
int *b = new int[];
int (*c)[2] = new
int[34][2];
int (*d)[2] = new int[][2];
int (*e)[2][3] = new int[34][2][3];
int (*f)[2][3] = new int[][2][3];
a[0] = 1;
b[0] = 1; //运行时错误,无分配的内存,b只起指针的作用,用来指向相应的数据
c[0][0] = 1;
d[0][0] = 1;//运行时错误,无分配的内存,d只起指针的作用,用来指向相应的数据
e[0][0][0] = 1;
f[0][0][0] = 1;//运行时错误,无分配的内存,f只起指针的作用,用来指向相应的数据
cout<<typeid(a).name()<<endl;
cout<<typeid(b).name()<<endl;
cout<<typeid(c).name()<<endl;
cout<<typeid(d).name()<<endl;
cout<<typeid(e).name()<<endl;
cout<<typeid(f).name()<<endl;
delete[] a; delete[] b; delete[] c;
delete[] d; delete[] e; delete[] f;
}
输出结果:
int *
int *
int (*)[2]
int (*)[2]
int (*)[2][3]
int (*)[2][3]