其实指针类型只是设定了这个指针可以取值的范围
比如int型的,表示4个字节,long为8个
如果把long型强制转换为int,那么就会被截掉4个字节子类和父类也是一样
一般来说,用一个父类的指针来指向一个子类的对象,是没有问题的(最多是截掉一些数据)
如果用一个子类的指针来指向一个父类的对象,就会出现越界的问题
很可能会出现编译错误或运行错误

解决方案 »

  1.   

    谢谢satty
    菜鸟在问你个问题:
    在CExTraceView::OnDraw(CDC* pDC)
    {
    CExTraceDoc* pDoc=GetDocument();
    }
    GetDocument()返回的是CDocument类对象指针,这是不是也是一种“一个子类的指针来指向一个父类的对象”,那它会有危险吗?
      

  2.   

    我想出错的应该是set_j的调用而不是delete,由于基类的指针在new的时候没有构造子类,在强制将基类指针转换为子类指针,但指针所指的实例仍不包括子类的成员,也就是j,这样引起没有分配的访问,在释放的时候就会出错。
      

  3.   

    我想出错的应该是set_j的调用而不是delete,由于基类的指针在new的时候没有构造子类,在强制将基类指针转换为子类指针,但指针所指的实例仍不包括子类的成员,也就是j,这样引起没有分配的访问,在释放的时候就会出错。
      

  4.   

    to devouer:
    你说的对,我屏蔽掉 pDClass->set_j (6);就可以成功释放掉指针了。可是为什么用debug跟踪到pDClass->set_j (6);后,不会出错,它还把后四个内存单元置成6,一直到delete才报错。是为什么呀?
      

  5.   

    这是因为在new后,如果操作系统为你分配的空间足够的大,因为每一次几字节的分会形成碎片,所以跟着的地址还可以来操作,但对于你的类来说,这是不可知的。结果也是没有定义的。
      

  6.   

    老兄,看来你对指针还不是很了解main()
    {
    CBaseClass* pBClass=new CBaseClass;  // pBClass 是一个指针,pDClass也是,只不过你为他们分配了空间而已
    CDerivedClass* pDClass=new CDerivedClass;
        pDClass=(CDerivedClass*)pBClass; 现在你将pDClass强制转换为派生类,派生类需要比基类多余的空间在那?————所以这一句有问题,并且pDClass原来分配的空间现在已经丢失了【pDClass已经指向别处了】
            pDClass->set_i (5);
            pDClass->set_j (6); 所以这一句也会错,不是函数错,而是派生类的j没空间
            delete pBClass;//为什么出错
    }
      

  7.   

    delete pBClass;//为什么出错
    至于这一句,如果你前面都没错的话,这一句也就没问题了
    解释他为什么错,就需要仔细看看候老先生的《深入浅出MFC》了——类在内存中的分配
      

  8.   

    谢谢devouer 
    我明白了,请帮忙看看这个问题:
    在CExTraceView::OnDraw(CDC* pDC)
    {
    CExTraceDoc* pDoc=GetDocument();
    }GetDocument()返回的是CDocument类对象指针,这是不是也是一种“一个子类的指针来指向一个父类的对象”?
    为什么不写成CExTraceDoc* pDoc=(CExTraceDoc*)GetDocument();
    那它会有危险吗?
      

  9.   

    to eion
     我说过它错了吗?我是说是它引起的错,如果觉得还要看《深入...》的话,不如看Lippman的《Inside the C++ Object Model》。
    一般情况是没有危险,因为你的视图类与文档类是靠文档模板来创建的,也就是它肯定是一个子类实例的针,如果引用CDocument也就是父类的东西,本来就没有问题,如果想用子类的东西,要一个显式的转换就行了,不过编译器会提醒你的。
      

  10.   

    《Inside the C++ Object Model》中讲得很清楚了
      

  11.   

    其实pDClass=(CDerivedClass*)pBClass;后,pDClass就不在指向new CDerivedClass的空间,而是指向new CBaseClass;通过pDClass调用Set_j()肯定会出错,因为CBaseClass根本没有实现这个函数。你能Debug进去因为虚函数表的原因,一旦你操作数据成员,退出时堆栈就会出错。至于GetDocument()你可以跟踪一下,就清楚了。实际上他是把派生类指针转换为父类指针,再返回给调用者。所以CExTraceDoc* pDoc=GetDocument();是不会出错的。一般来说向上转换是安全的,因为派生类在构造时,必定先要构造父类。向下转换是不安全的,因为父类构造了,子类不一定构造了。所以在转换时都会使用dynamic_cast操作符,以确保转换安全。snoopyll:你最好看看《深度探索C++模型》一书,那里讲得很清楚C++类的内存模型。
      

  12.   

    to snoopyll:  在你的CExTraceView中,GetDocument难道没有被重载么?(由MFC完成),如果没有被重载的话,那不报错的话就真的奇怪了,如果重载了,你就会发现那不是"一个子类的指针来指向一个父类的对象"了
      

  13.   

    实际上指针的强制转换,编译器并没有作任何事情,只不过是语法的要求而已【免得你的指针乱指】你甚至可以是
    int x;
    void *vp = &x;
    float *pf = (float*)vp;
    cout<<*pf;指针的强制转换就是将内存断看作是什么样的结构而已,你看着一段代码,VC会给你错误提示吗?NONE!
    struct AA
    {
        int x;
    public:
        int get(){return x;}
    };
    void *p=NULL;
    AA *pV = (AA*)pV;
    注意——指针只有4个字节,它能干吗?所以别指望指针自己给你做多少,自己维护吧
      

  14.   

    void *p=NULL;
    AA *pV = (AA*)pV;
    改为
    char x=0;
    void *p=&x;
    AA *pV = (AA*)p;