前言
多态的本质在于:通过操作指向bc对象的指针或引用来操作dc对象,这样子引用或指针看起来就如同有多种类型。数组也可以使用多态,但其结果几乎不可能与你的预期结果一致。
问题实例
假设有一个类BST(比如是搜索树对象)和继承自BST类的派生类BalancedBST:1
2class BST { ... };
class BalancedBST: public BST { ... };
现有一个遍历函数:1
2
3
4
5void printBSTArray(ostream& s,const BST array[],int numElements){
for (int i = 0; i < numElements;++i) {
s << array[i];
}
}
当我们将含有BalancedBST对象的数组变量传递给遍历函数时,后果如何?1
2BalancedBST bBSTArray[10];
printBSTArray(cout, bBSTArray, 10);
答案是编译通过,但无法正常运行。
问题剖析
原因很简单:1
2
3for (int i = 0; i < numElements;++i) {
s << array[i];
}
array[i]等价于*(array+i),而指针的加法又等价于地址+=i*sizeof(element)
,一般我们认为sizeof(dc)>=sizeof(bc)
,所以上述代码会产生不可预期的后果。
删除数组
如果我们试图通过一个bc指针去删除dc数组,那么结果也会崩溃,有实例如下:1
2
3
4
5
6void deleteArray(BST array[]){
delete [] array;
}
BalancedBST *balTreeArray = new BalancedBST[50];
...
deleteArray(balTreeArray);
当数组被删除时,每一个元素的destructor都会被调用,所以当执行delete[] array
时,实际上执行了如下代码:1
2
3while(...)
array[i].BST::~BST();
}
C++明确规定,由bc的引用或者指针删除dc,其结果未定义。
总结
简单的说,多态和指针算术不能混用.又由于数组总是会牵扯一些指针算术,所以多态和数组也不能混用。
一般而言,如果你尽量“不用一个具体类继承自另一个具体类”,那你应该会很少犯这种错误。