回 帖 发 新 帖 刷新版面

主题:[原创]指针的深入理解-初学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()。
         不知道我描述的怎么样,希望对你们能有所帮助。

回复列表 (共16个回复)

11 楼

我想我把名称改成“C++进阶者必看”
你还有无语啊。

如果想提高C++水平
建意多看点“深入C++系列”的书籍

如果你看的很晕,我想你的指针一定存在问题。
这里有一道面试试题。
如果你能把它理解清楚,本贴对你说就不是问题咯。你看一下下面的这个链接吧!

http://www.programfan.com/club/showbbs.asp?id=172047

12 楼

不学汇编
是不会理解到哪里去的

13 楼

说的也有道理,学了汇编理解的是要深刻一些。

14 楼

........

15 楼

我晚上太晚了,头脑不清新,我明天再看,先顶下先。。

16 楼

[size=4]Please don't waste your time to read something claim it is "初学C++者必看"!

It is better called as "初学C++者不看,大家不必看"

谢谢![/size]

我来回复

您尚未登录,请登录后再回复。点此登录或注册