<b>More Effective C++:不利用多态性数组</b>[VC/C++编程]
本文“<b>More Effective C++:不利用多态性数组</b>[VC/C++编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
类担当的最重要的特点是你可以通过基类指针或引用来操作派生类.这样的指针或引用具有行为的多态性,就仿佛它们同时具有多种形状.C++答应你通过基类指针和引用来操作派生类数组.不过这根本就不是一个特点,因为这样的代码根本无法如你所愿地那样运行.
假定你有一个类BST(比方是搜索树对象)和担当自BST类的派生类BalancedBST:
class BST { ... };
class BalancedBST: public BST { ... };
在一个真实的程序里,这样的类应当是模板类,但是在这个例子里并不重要,加上模板只会使得代码更难阅读.为了便于谈论,我们假定BST和BalancedBST只包含int范例数据.
有这样一个函数,它能打印出BST类数组中每一个BST对象的内容:
void printBSTArray(ostream& s,
const BST array[],
int numElements)
{
for (int i = 0; i < numElements; ) {
s << array[i]; //假定BST类
} //重载了操作符<<
}
当你传送给该函数一个含有BST对象的数组变量时,它可以正常运行:
BST BSTArray[10];
...
printBSTArray(cout, BSTArray, 10); // 运行正常
但是,请考虑一下,当你把含有BalancedBST对象的数组变量传送给printBSTArray函数时,会产生什么样的后果:
BalancedBST bBSTArray[10];
...
printBSTArray(cout, bBSTArray, 10); // 还会运行正常么?
你的编译器将会毫无告诫地编译这个函数,但是再看一下这个函数的循环代码:
for (int i = 0; i < numElements; ) {
s << array[i];
}
这里的array[I]只是一个指针算法的缩写:它所代表的是*(array).我们知道array是一个指向数组起始地址的指针,但是array中各元素内存地址与数组的起始地址的隔断毕竟有多大呢?它们的隔断是i*sizeof(一个在数组里的对象),因为在array数组[0]到[I]间有I个对象.编译器为了成立精确遍历数组的履行代码,它必须可以肯定数组中对象的大小,这对编译器来说是很简单做到的.参数array被声明为BST范例,所以array数组中每一个元素都是BST范例,因此每个元素与数组起始地址的隔断是be i*sizeof(BST).
至少你的编译器是这么认为的.但是假如你把一个含有BalancedBST对象的数组变量传送给printBSTArray函数,你的编译器就会出错误.在这种情形下,编译器原先已经假定数组中元素与BST对象的大小一致,但是目前数组中每一个对象大小却与BalancedBST一致.派生类的长度普通都比基类要长.我们猜想BalancedBST对象长度的比BST长.假如如此的话,printBSTArray函数生成的指针算法将是错误的,没有人知道假如用BalancedBST数组来履行printBSTArray函数将会发生什么样的后果.不管是什么后果都是令人不高兴的.
假如你试图删除一个含有派生类对象的数组,将会发生各种各样的问题.以下是一种你大概的不精确的做法.
//删除一个数组, 但是首先记录一个删除信息
void deleteArray(ostream& logStream, BST array[])
{
logStream << "Deleting array at address "
<< static_cast(array) << '
';
delete [] array;
}
BalancedBST *balTreeArray = // 成立一个BalancedBST对象数组
new BalancedBST[50];
...
deleteArray(cout, balTreeArray); // 记录这个删除操作
这里面也遮盖着你看不到的指针算法.当一个数组被删除时,每一个数组元素的析构函数也会被调用.当编译器碰到这样的代码:
delete [] array;
它必定象这样生成代码:
// 以与构造次序相反的次序来
// 解构array数组里的对象
for ( int i = 数组元素的个数 1; i >= 0;--i)
{
array[i].BST::~BST(); // 调用 array[i]的
} // 析构函数
因为你所编写的循环语句根本不能正运行,所以当编译成可履行代码后,也不大概正常运行.语言标准中说通过一个基类指针来删除一个含有派生类对象的数组,后果将是不肯定的.这实际意味着履行这样的代码必定不会有什么好后果.多态和指针算法不能混合在一同来用,所以数组与多态也不能用在一同.
值得注意的是假如你不从一个具体类(concrete classes)(比方BST)派生出另一个具体类(比方BalancedBST),那么你就不太大概犯这种利用多态性数组的错误.正如我在背面将介绍的条款33所注释的,不从具体类派生出具体类有很多好处.
以上是“<b>More Effective C++:不利用多态性数组</b>[VC/C++编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |