More Effective C++:不利用多态性数组
当前位置:以往代写 > C/C++ 教程 >More Effective C++:不利用多态性数组
2019-06-13

More Effective C++:不利用多态性数组

More Effective 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所表明的,不从详细类派生出详细类有许多长处。

    关键字:

在线提交作业