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

基础知识:

 

Ø         数组:在C/C++中,数组是一块连续的内存,内存中数组元素紧密地排列在一起。内存的大小 = 元素个数 x 单个元素的大小。

 

Ø         操作符[]:使用索引访问数据中的元素。元素在内存中的位置为:数组开始位置 + 索引 x单个元素的大小。

 

Ø        类的实例类的实例也占用内存。类占内存的大小和类的数据成员有关,类的数据成员越多,那么占用的内存也越大

 

Ø         子类和父类的内存分配:父类中的数据成员在前,子类的数据成员在后。

 

Ø         指针的加减法:当指针加减一个整数时,实际的指针位置加减量为:该整数 * 指向类型的大小。如int *p; p+1的结果是p指向位置后的第4个字节。

 

Ø         delete []:删除数据。从指针位置开始删除数组元素,一直到内存块结束。对于类数组,会对每个元素调用析构函数。

 

子类数组

 

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

 

 

使用父类指针时的操作分析

 

把一个子类数组变量赋值给一个数据元素父类的指针时,指针首先指向数组头的位置(如图)。

 

操作1:访问元素

访问第一个元素(元素0)时,没有任何问题。

访问下一个元素时,指针后移。按正常用法使用++操作或+=1操作。因为该指针是父类指针,所以偏移量为父类的大小sizeof(父类)。这时指针将指向图中“子类数据”的位置,而不是元素1的位置。这将导致出错。使用[]操作访问时也有同样的问题。

 

操作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类的大小,会发现它们是相同的。所以无论使用子类指针还是父类指针,元素定位的计算结果都一样。

 

总结:

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

 

作者:苏林

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值