继承的重要性质之一:通过“指向基类的指针或引用”,操作继承类对象。
如此的指针或引用,其行为是多态的。
c++允许通过“基类的指针和引用”来操作“继承类对象形成的数组”。但是:
1、
class BST{...};
class BalanceBST:public BST{...};
void printBSTArray(ostream& s,const BST array[],int numElements)
{
for(int i=0;i<numElements;++i)
{
s<<array[i];//假设BST对象有一个operator<<可用
}
}
//将由BST对象组成的数组传给以上函数没问题
BST BSTArray[10];
...
printBSTArray(cout,BSTArray,10);//运行良好
//将一个由BalanceBST对象组成的数组传给以上函数:
BalanceBST bBSTArray[10];
...
printBSTArray(cout,bBSTArray,10);//运行结果不可预期
因为:
array[i]代表*(array+i)。array是个指向数组起始处的指针。array所指内存与array+i所指内存相距i*sizeof(数组中对象)。
为让编译器所产生代码能走访整个数组,编译器必须有能力决定数组中的对象大小。以上代码中array和array+i相距i*sizeof(BST)。
若给printBSTArray函数传一个由BalanceBST对象组成的数组,编译器会误导。此时它仍假设数组中每一元素大小为sizeof(BST),但其实每一元素大小为sizeof(BalanceBST)。这样编译器为printBSTArray函数产生的array[i]对于BalanceBST对象组成的数组而言是错的,不可预期。
继承类对象通常会比基类对象大(继承类通常比基类有更多数据成员)。
2、
通过基类指针删除一个由继承类对象组成的数组:
void deleteArray(ostream& logStream,BST array[])
{
logStream<<static_cast<void*>(array);
delete []array;
}
BalanceBST *balTreeArray=new BalanceBST[50];//产生一个BalanceBST数组
...
deleteArray(cout,balTreeArray);//记录此删除动作
当数组被删除,数组中每一个元素的destructor都必须被调用,当编译器看到:
delete []array;
会产生代码:
for(int i=数组中元素数目-1;i>=0;--i)
{
array[i].BST::~BST();//调用array[i]的destructor
}
c++语言规范中说:
通过基类指针删除一个由继承类对象构成的数组,其结果未定义。(以上编译器产生的代码是行为错误的循环)
多态和数组不能混用。(数组对象几乎总是涉及指针的算术运算)