一.
怎样给多维数组动态分配内存
//Allocate:
int **p = new int* [m];
for(int i = 0 ; i < m ; i++)
p[i] = new int[n];
//Use:
for(int i = 0 ; i < m; i++)
for(int j = 0 ; j < n ; j++)
p[i][j] = i * j;
//Free:
for(int i = 0 ; i < m ; i++)
delete[] p[i];
delete[] p;
二.
字符数组V字符串指针:
字符数组如果在函数里声明则在栈上分配内存空间.
char a[1034]="bac" --true,这时可以改变a地址范围内的任一地址所指向的内容.如:a[0]='a'.而a的值一般是不变的,除非重新分配地址.
char a[1034]; a="bac" --faile 因为"abc"有const char*类型的,而a是char的.
strcpy(a,"abc"); -true
如果声明字符串指针char *a ="abc"常量,当把常量赋给一个指针(a)时,则a是在静态存储空间分配内存,原则上a地址里范围内指向的内容不可以改变.
char *a="abc"; a="bcd" --true 可以改变a的值,但不可以改变这个地址里范围内指向的内容. char *a; a="abc"; --true
char *a="abc"; a[1]='d'; -false
strcpy(a,"abc") --false *a的值不可变
char *a=malloc(size); --则a在堆分配空间,相当于char a[size],用free释放内存
char *a=new char(size); --同上,不过要用delete释放内存
这时strcpy(a,"abc"); a[n]='d'; --true
三.多态:
#include<iostream>
using namespace std;
class a
{
public:
a() : b(1234){}
int b;
virtual int get()
{
cout<<"a::get()";
return b;
}
};
class c :public a
{
public:
c() : d(2345){}
int d;
int add()
{
return d+7;
}
int get()
{
cout<<"c::get()";
return d;
}
};
/*void fun(a &www)//第一版本
{
cout<<www.get() << endl;
}*/
void fun(a www)//第二版本
{
cout<<www.get() << endl;
}
int main()
{
a *pa;
c cc;
pa=&cc;//很正常
cout<<pa->get()<<endl;//调用了c类的函数
c* pc;
a aa;
pc=(c*)&aa;//这句强制转换
cout<<pc->get()<<endl;//调用了a类的函数
cout<<pc->add()<<endl;//此句会出错!?虽然pc是指向a对象,但是他却成功的调用了c中的add();这是为何?
fun(cc);//使用第一 版本就调用c,使用第二版本就调用a
fun(aa);//使用第一版本就调用a,使用第二版本就调用a
return 0;
}
int main()中前6行是没有问题的。
第7行,pc = (c*) &aa;就是把强行把派生类的指针指向基类的对象,这是危险的操作,但不会发生对象切割,因为这只是修改了一个指针,并没有对类的对象去实施什么破坏性的操作。
45: pc=(c*)&aa;//这句强制转换
004016C8 lea eax,[ebp-1ch]
004016CB mov dword ptr [ebp-14h],eax
从汇编上看出,它只是把aa对象的地址ebp-1ch放到了pc所占的内存中ebp-14h中,没有动aa对象ebp-1ch附近的内容,所以不会数据丢失。
cout<<pc->get()<<endl;凑合着可以运行,因为get本身是a类的一个成员函数,因为它是虚的,所以这里调用的是a类的函数。
cout<<pc->add()<<endl;这也凑合着可以运行,因为虽然a类中没有add()函数,但因为c类中的add()不是虚的,所以这里做静态绑定,调用了c类的add()函数。因为add()函数中对一个a类中不存在成员d进行了加7操作,所以就返回了一个无效的数字。可以从输出结果中清楚的看到。
004016FD mov ecx,dword ptr [ebp-14h]
00401700 call @ILT+415(c::add) (004011a4)
从汇编上看出,这里没有用虚函数的机制,只是一个静态绑定。
如果把add也改成virtual的,这里就会做动态绑定
00401704 mov ecx,dword ptr [ebp-14h]
00401707 call dword ptr [edx+4]
结果就更离奇了,您可以自己试试。
对于这一点,为什么可以正常调用(但结果不对)非虚的add()函数,可以再参考我在另一个贴中的回复。
http://expert.csdn.net/Expert/topic/1414/1414072.xml?temp=.8994867
下面解释func:
第一版本是传引用,就相当于是传了指针,所以可以实现多态。func(cc)会调用c的get(),func(aa)会调a的get()。
004016DF lea ecx,[ebp-1Ch]
004016E2 push ecx
004016E3 call @ILT+350(fun) (00401163)
可看出,只用堆栈传了指针,没有挎贝对象。
第二版本是传对象,会调挎贝构造函数,这里没有定义,所以就进行了默认的挎贝。因为形参是基类a的,它不知道c又在它身上加了d这个成员,所以它就把一个c的对象挎贝成了a的对象,a中没有的成员d就被切割了。所以func(cc)和func(aa)都只会调a的成员函数get()。这种现象就是所谓的“对象切割”,经过挎贝后,c的对象被切割得只剩下a的部分了。
0040172C call @ILT+115(a::a) (00401078)
00401731 call @ILT+640(fun) (00401285)
很明显调了a的挎贝构造函数,对象被切割。