主题:[原创]指针的深入理解-初学C++者必看
--小峰
下面我们从两个例子中分析一下,指针到底是怎么灵活的.
第一个例子:
#include "stdafx.h"
#include "iostream.h"
class ClassUShort
{
public :
unsigned short v1,v2;
ClassUShort(int e1,int e2)
{
v1=e1;v2=e2;
cout<<"v1的地址是:"<<&v1<<endl;
}
void show(){cout<<"v1="<<v1<<","<<"v2="<<v2<<endl;}
};
class ClassInt
{
int v3;
public:
ClassInt(int e=3){ v3=e;}
void show()
{
cout<<"this指针的值是:"<<this<<endl;
cout<<"v3的地址是:"<<&v3<<endl;
cout<<"v3="<<v3<<endl;
}
};
int main(int argc, char* argv[])
{
ClassUShort usObj(0,1);
ClassInt *pIntObj;
pIntObj=(ClassInt *)&usObj;
cout<<"对象usObj的地址是:"<<&usObj<<endl;
cout<<"指向对象usObj的指针pIntObj的值是:"<<pIntObj<<endl;
pIntObj->show();
unsigned short *pSInt;
pSInt=(unsigned short *)&usObj;
pSInt++;
cout<<"pSint++之后,(*pSInt)的值是:"<<*pSInt<<endl;
cin.get();
return 0;
}
程序的运行结果为:
v1的地址是: 0x0012FF7C
对象usObj的地址是:0x0012FF7C
指向对象usObj的指针pIntObj的值是:0x0012FF7C
this指针的值是:0x0012FF7C
v3的地址是: 0x0012FF7C
v3=65536
pSint++之后,(*pSInt)的值是:1
从运行结果中也许你还正在怀疑,v3的值为什么是65536。在ClassUShort中定义的两个unsigned short的变量,在ClassInt中只定义的一个int型的变量。在main函数中, 通过pIntObj=(ClassInt *)&usObj作了一个强制类型转换,使指针pIntObj的值为对象usObj有地址0x0012FF7C,由于pIntObj是ClassInt类型,所以pIntObj->show()调用的就是ClassInt的成员函数,在pIntObj->show()之前ClassInt没有任何一个实例,只有一个ClassInt类型的指针pIntObj,所以ClassInt类中的数据成员v3是没有被分配存储空间的。
在类中没有虚函数存在的情况下,类的第一个数据成员的地址和此类的对象的首地址相等,也就是说v3的地址为pIntObj的值,即和usObj的地址相等,数据成员v1的地址与对象usObj的地址相等。为什么v3的地址为pIntObj的值,你可以这样想象,假设pIntObj=new ClassInt此时v3的地址为pIntObj的值也就不难理解了吧!(如果类中包含任何一个虚函数情况又不一样,即包含虚函数的类会存在一个指向虚函数地址表的一个32位的指针成员,并且将这个指针的地址和对象的首地址相等),此时在ClassInt::show()函数中访问v3也就相当于在访问以0x0012FF7C为首地址的前4个字节的内容,即0x0012FF7C-0x0012FF7F的内容,之所以是前4个字节是因为v3是int类型。由于v3的地址和pIntObj指向的对象usObj的地址相等,又因为v1的地址为usObj的地址相等,所以v1和v3的地址也相等。访问v3相当于在访问usObj的数据成员v1和v2,为什么这里把v2也扯进来,因为v1和v2是unsigned short无符号的短整型各占2个字节的空间(int 占4个字节), 在访问以0x0012FF7C为首地址的前4个字节的内容时自然也就把v2给访问了,v2的地址一定是: 0x0012FF7E。
以0x0012FF7C为首地址的前4个字节的内容到底是什么呢?它肯定存储的是v1,v2的值了,即分别是0和1,0和1在内存中的存储事实并不是很直接为0000 0001的,而是按照低字、低字节在前的存储方式进行的,
因为v1,v2为short,所以应低字节在前即v1为0000 ,v2为0100,即v1和v2的存储格式是0000 0100。因为v3为四个字节的整型,所以应是低字在前,即将0000 0100转换成0100 0000,然后再按低字节在前的规则即将0100变成0001、将0000还是0000,转换完毕的16进制为00010000。而将十六进制00010000转换成十进制就为65536,所以v3的值就变成的65536。
在这里我也随便举了一个短整型指针指向一个类的对象的一个例子: pSInt=(unsigned short *)&usObj,此时pSInt的值也为usObj的地址: 0x0012FF7C,然后pSInt++,因为短整型占二个字节,所以pSInt++之后,pSInt的值也就成子v2的地址: 0x0012FF7E,所以最后*pSInt的输出结果为1。
第二个例子:
#include "stdafx.h"
#include "iostream.h"
class CDocument
{
public:
void show(){cout<<"CDocument::show()被调用\n";}
void fun(){this->Print();}
virtual void Print(){cout<<"CDocument::Print()被调用\n";}
};
class CMyDoc:public CDocument
{
public:
void show(){cout<<"CMyDoc::show()被调用\n";}
void Print(){cout<<"CMyDoc::Print()被调用\n";}
};
int main(int argc, char* argv[])
{
CMyDoc myDoc;
CDocument *p;
p=((CDocument *)&myDoc);
p->show();
p->fun();
cin.get();
return 0;
}
运行结果为:
CDocument::show()被调用
CMyDoc::Print()被调用
在理解上一个例子的基础上理解这个例子也就很容易的,指向p的值虽然是myDoc的地址,但是仍是CDocument类型的指针,所以p->Show调用的就是CDocument::show()。
在p->fun()调用CDocument::fun()时,成员函数fun()中的this指针和p是相等的,因为p指向myDoc即this也指向myDoc, 又因为Print()是一个虚函数,并且在派生类CmyDoc也改写此这个虚函数,所以fun()中的this->Print()自然调用的也就是CMyDoc::Print()。
不知道我描述的怎么样,希望对你们能有所帮助。