More Effective C++ 条款03:绝对不要以多态方式处理数组

class BST {...};
class BalancedBST : public BST
{
    ...
};

现在考虑有个函数,用来打印BSTs数组中的每一个BSTs数组中的每一个BST的内容:

void printBSTArray(ostream& s, const BST array[], int numElements)
{
    for(int i = 0; i < numElements; ++i){
        s << array[i];   //假设BST objects有一个 operator << 可用
    }
}

将一个BST对象组成的数组传给此函数,没问题

BST BSTArray[10];
printBSTArray(cout, BSTArray, 10);  //运行良好

然而如果将一个BalancedBST对象所组成的数组交给printBSTArray函数,会发生什么什么事:

BalancedBST bBSTArray[10];
printBSTArray(cout, bBSTArray, 10); //运行结果不对

array[i]其实是一个“指针算数表达式”的缩写:它代表的其实是*(array + i)。我们知道array是个指针,指向数组起始处。array所指内存和array+i所指的内存两者相距多远?答案是 i*sizeof(数组中的对象),因为array[0]和array[i]之间有i个对象,为了让编译器所产生的代码能够正确走访整个数组,编译器必须有能力决定数组中的对象大小。很容易呀,参数array不是被声明为“类型为BST”的数组吗?所以数组中的每个元素必然都是BST对象,所以array和array+i之间的距离一定是i*sizeof(BST)。但如果你交给printBSTArray函数一个由BalancedBST对象组成的数组,你的编译器就会被误导。这种情况下,它仍然假设数组中每个元素的大小是BST的大小,但其实每一个元素的大小是BalancedBST的大小。由于derived classes通常比其base classes有更多的data members,所以子类对象都比基类对象大得多。因此,我们我们合理地预期一个BalancedBST对象比一个BST对象大,如果是这样,编译器为printBSTArray函数所产生的指针算数表达式,对于BalancedBST对象所组成的数组而言就是错误的。

如果尝试通过基类指针删除一个由子类对象组成的数组,那么同样有错误:

void deleteArray(ostream& logStream, BST array[])
{
    logStream << "Delete array at address " << static_cast<void*>(array) << endl;

    delete [] array;
}

BalancedBST *balTreeArray = new BalancedBST[50]; //产生一个BalancedBST数组
deleteArra(cout, balTreeArray);

delete []array;

必须产出类似这样的代码:

for(int i = the number of elements in the array - 1; i >= 0; --i)
{
    array[i].BST::~BST(); //调用array[i]的destructor
}

通过base class 删除一个由子类对象构成的数组,其结果未定义。

总结:多态和指针算数不能混用。

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:我行我“速” 设计师:Amelia_0503 返回首页
评论

打赏作者

娱乐界祖师爷

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值