回 帖 发 新 帖 刷新版面

主题:[原创]指针的深入理解-初学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个回复)

沙发

I don't think understanding polymorphism/virtual function requires to know implementation details such as what is the pointer value etc. 

Also, implementation detail can vary from compiler to compiler!

Teaching beginner implementation detail to understand polymorphism/virtual funtion is misleading!!!!

Sorry, I don't think this is a good article for beginners!!!!

Thanks!

板凳

[quote]指针的深入理解-初学C++者必看[/quote]

The title is really misleading for 初学C++者!!!

3 楼

解析这个需要弄得这么复杂吗?汗。。。。
感觉还是先学好C,再学C++会比较正统。。。

4 楼

[quote]感觉还是先学好C,再学C++会比较正统。。。[/quote]

No, just opposite!!!!

Learning OO is much harder for good C programmers than novice!

Switching thinking is much harder than learning a new syntax!

I guess the author might be a victom of knowing too much C! Of course, I could be wrong on this... I am sorry, if I were wrong! 

[em15][em15][em15]

5 楼

to 4 floor
what a poor English you use,I am sorry to say that.But my tolerance is limited.there are so many error in your sentence.take more care about them next time please!!

6 楼

[em1] Welcome to the team!!!

[url=http://www.programfan.com/club/showbbs.asp?id=138954][原创]justforfun626 祝大家狗年快乐!!! [/url]

Thanks!

7 楼

Chinese English. unbearable

8 楼

一楼的朋友你好,其实你也说的有道理,本贴对初学者来说可以能是会被之误导.但是指针的功能确实很强大,在C++中它与多态接合的也很紧密.所以说在了解虚函数的情况下看这此内容对他一定会很有帮助的.

第一个例子程序根本就不需要知道虚函数就可以阅读的.这一些对高手来说可以并不算什么,但如果初学者能理解第一个例子,他一定会得到收获的,至少说在程序中看到一些比较复杂的强制类型转换的语句时不会太忙然.

谢谢你的关注.我不想说的更多!!!

9 楼

看得真的有点晕啊

10 楼

[quote]看得真的有点晕啊[/quote]

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

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

谢谢!

我来回复

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