您的位置:首页 > 编程语言 > C语言/C++

C++中使用基类指针操作子类数组的分析

2008-03-29 21:10 936 查看
基础知识:
 

Ø         数组:在C/C++中,数组是一块连续的内存,内存中数组元素紧密地排列在一起。内存的大小 = 元素个数 x 单个元素的大小。
 
Ø         操作符[]:使用索引访问数据中的元素。元素在内存中的位置为:数组开始位置 + 索引 x单个元素的大小。
 
Ø        类的实例:类的实例也占用内存。类占内存的大小和类的数据成员有关,类的数据成员越多,那么占用的内存也越大。
 
Ø         子类和父类的内存分配:父类中的数据成员在前,子类的数据成员在后。
 
Ø         指针的加减法:当指针加减一个整数时,实际的指针位置加减量为:该整数 * 指向类型的大小。如int *p; p+1的结果是p指向位置后的第4个字节。
 
Ø         delete []:删除数据。从指针位置开始删除数组元素,一直到内存块结束。对于类数组,会对每个元素调用析构函数。
 

子类数组
 
基于以上知识,子类数组的内存分布可以粗略表示为下图:


 

 
使用父类指针时的操作分析
 
把一个子类数组变量赋值给一个数据元素父类的指针时,指针首先指向数组头的位置(如图)。
 
操作1:访问元素
访问第一个元素(元素0)时,没有任何问题。
访问下一个元素时,指针后移。按正常用法使用++操作或+=1操作。因为该指针是父类指针,所以偏移量为父类的大小sizeof(父类)。这时指针将指向图中“子类数据”的位置,而不是元素1的位置。这将导致出错。使用[]操作访问时也有同样的问题。
b538
 

操作2:使用delete[]删除数据:
delete[]同样是按访问元素的方法逐个析构这些元素。因为它无法找到对象真正的起始位置。
 

特殊情况
在CSDN的讨论中,有人写出了验证代码,证明这样访问没有问题,如Chappell的代码:
  

#include <iostream.h>

class Base

{

public:

    Base()

    {

        cout<<"Base()"<<endl;

    }

    virtual ~Base()

    {

        cout<<"~Base()"<<endl;

    }

};

class Child:public Base

{

public:

    Child()

    {

        cout<<"Child()"<<endl;

    }

    virtual ~Child()

    {

        cout<<"~Child()"<<endl;

    }

};

int main(int argc, char* argv[])

{

    Base* pBase = new Child[3];

    delete []pBase;

    return 0;

}

 
这段代码可以正确运行,但与刚才所说的并不矛盾。这段代码中的Child类属于特例,因为它没有数据成员,子类数据是空的。这时如果使用sizeof来检查Child类和Base类的大小,会发现它们是相同的。所以无论使用子类指针还是父类指针,元素定位的计算结果都一样。
 
总结:

不要用父类指针去操作子类数组,虽然你可能碰巧不出错。
 

作者:苏林
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ delete class
相关文章推荐