C++以多态方式处理数组可能会遇到的问题
今天读《More Effective C++》时遇到一个条款:绝对不要以多态方式处理数组。以前自己也没有注意过,觉得有必要记录下来。
C++是允许通过base class的指针或引用来操作derived class所形成的数组的。但发生的事情可能会令你感到意外。下面举例说明:
基类和派生类是这样的:
class BST /*base class*/
{
public:
BST() : x1() {}
virtual ~BST()
{
cout << "Good Bye BST." << endl;
}
int x1;
}; class BalancedBST : public BST /*derived class*/
{
public:
BalancedBST() : BST(), x2() {}
virtual ~BalancedBST()
{
cout << "Good Bye BalancedBST." << endl;
}
int x2;
};
下面我重载了两个输出操作符:
/*输出base class*/
ostream& operator<<(ostream& os, const BST& obj)
{
os << "class BST: " << obj.x1 << endl;
return os;
} /*输出derived class*/
ostream& operator<<(ostream& os, const BalancedBST& obj)
{
os << "Class BalancedBST: " << obj.x1 << ' ' << obj.x2 << endl;
return os;
}
下面这个函数用于输出base class和derived class的数组。
/*输出base class和derived class数组*/
void Print(ostream& os, const BST arr[], int n)
{
for (int i = ; i < n; ++i)
{
os << arr[i];
}
}
当以如下方式测试时,没有问题。
BST baseArr[];
Print(cout, baseArr, ); //好的,没问题,正常
当以如下方式测试时,就会出现问题。
BalancedBST deriveArr[];
Print(cout, deriveArr, ); //出错啦

编译器要想遍历数组中每一个元素,它必须知道每一个元素的大小。很明显,当print参数为BalancedBST数组时,编译器静态的将其数组大小当作BST的大小处理,以*(i+arr)的方式前进,结果是未知的。
还有一种情况,就是通过一个base class指针,删除一个由derived class组成的数组。
当以如下方式测试时,没有问题。
BST *base = new BST[];
delete [] base; //好的,没有问题 BalancedBST *derived = new BalancedBST[];
delete [] derived; //好的,没有问题
当我以如下方式测试时,就会有问题。

当数组被删除时,数组中每个元素的destructor会被调用,调用的顺序与构造顺序相反。也就是说执行delete [] base语句时,会产生类似下面的代码。
for (int i = ; i >= ; --i) //编译器产生类似的代码,但是是错误的。
{
base[i].BST::~BST();
}
根本原因还是编译器把derived class数组成员的大小当作base class来计算数组元素的位置。
C++规定,通过base class指针删除一个由derived class objects构成的数组,其结果是未定义的。所以,多态和指针算术不能混用,数组对象几乎总会涉及指针的算术运算,因而数组和多态不要混用。
C++以多态方式处理数组可能会遇到的问题的更多相关文章
- 【M3】绝对不要以多态方式处理数组
1.考虑下面的情况,有个方法,如下: void Print(ostream& s, const Base array[], int size) { for(int i=0; i< siz ...
- 【More Effective C++ 条款3】最好不要以多态方式处理数组
1.在数组与多态混用的情况下,数组元素的访问会出现不可预期的结果(因为数组元素的访问会使用到下标运算) 将一个子类对象数组传递给一个父类对象数组声明的函数,编译器会允许这个行为,但是由于子类对象和父类 ...
- 在ASP.NET MVC中以post方式传递数组参数的示例
最近在工作中用到了在ASP.NET MVC中以post方式传递数组参数的情况,记录下来,以供参考. 一.准备参数对象 在本例中,我会传递两个数组参数:一个字符串数组,一个自定义对象数组.这个自定义对象 ...
- URL 通过Get方式传递数组参数
URL 通过Get方式传递数组参数 方法1: ?id=1&id=2&id=3 后台获取时,只需要reqeust.getParameterValues("id") 获 ...
- 出于性能考虑,C语言自动地以传地址的方式将数组传递给被调函数 const 编译错误 最小权限原则
#include <stdio.h> int main(void) { char array[5]; printf("array=%p,&array[0]=%p,& ...
- 在ASP.NET MVC中以post方式传递数组参数的示例【转】
最近在工作中用到了在ASP.NET MVC中以post方式传递数组参数的情况,记录下来,以供参考. 一.准备参数对象 在本例中,我会传递两个数组参数:一个字符串数组,一个自定义对象数组.这个自定义对象 ...
- 用最复杂的方式学会数组(Python实现动态数组)
Python序列类型 在本博客中,我们将学习探讨Python的各种"序列"类,内置的三大常用数据结构--列表类(list).元组类(tuple)和字符串类(str). 不知道你发现 ...
- 用递归的方式处理数组 && 把递归方法方法定义到数组的原型上 (这是一次脑洞大开的神奇尝试)
在 javascript 里,如果我们想用一个函数处理数组 (Array) 中的每个元素,那我们有很多种选择,最简单的当然就是用自带的 forEach 函数(低版本也可以使用 lodash 中的 fo ...
- 以forin的方式遍历数组时进行删除操作的注意点
今天在修改某项需求的时候,需要在遍历的时候将匹配项移除掉,采用的时forin的方式遍历,然后运行的时候却crash掉了 for (NSString*str in self.btnArray) { if ...
随机推荐
- servlet中通过getWriter()获取out返回给浏览器出现中文乱码问题
感谢博主https://blog.csdn.net/louyongfeng3613/article/details/50160317 在Servlet编程中,经常需要通过response对象将一些信息 ...
- Eclipse配置多个jdk
Eclipse配置多个jdk 步骤: 1,打开windows > Preferences: 2,点击“Add”,新增jdk,选择“Standard VM”: 3,下一步,选择对应版本的jer: ...
- excel表中同一列相同内容进行合并
如下图所示一张表格,如果想要把表格中相同考号的信息合并来查看的话,首先我们先通过表格的排序功能,把相同的内容先排列在一起.在数据选项卡下找到排序点就可以. 第二步,选中整个数据区域,在数据选项卡下 ...
- spark SQL学习(spark连接 mysql)
spark连接mysql(打jar包方式) package wujiadong_sparkSQL import java.util.Properties import org.apache.spark ...
- Sqoop-问题
1.权限问题 // :: INFO mapreduce.Job: Job job_1555064328415_0328 failed with state FAILED due to: Job set ...
- codeforce AIM tech Round 4 div 2 B rectangles
2017-08-25 15:32:14 writer:pprp 题目: B. Rectangles time limit per test 1 second memory limit per test ...
- 安装mysql数据库中的技巧、错误排查
针对解压版本5.7.16(博主使用的这个版本.在某些低版本中部分命令失效) 一.安装.初始化data目录(解压版解压后没有data目录) 安装:配置path环境变量,然后管理员运行命令提示符cmd ...
- 实现基本的Ajax和Json请求
前面已经封装好了一个方法ajax(),通过这个方法可以实现Ajax请求,接下来就是给出 例程来测试这个方法和实现简单的功能. 视图的部分代码如下: <body> <div> ...
- 【Python】关于使用pycharm遇到只能使用unittest方式运行,无法直接选择Run
相信大家可能都遇到过这个问题,使用pycharm直接运行脚本的时候,只能选择unittest的方式,能愁死个人
- 毕业设计总结(1)-canvas画图
去年6月底完成的毕业设计,到现在也才开始给它做个总结,里面有很多可以学习和借鉴的东西. 我的毕业设计的题目是“一种路径规划算法的改进与设计”,具体的要求可参见下面的表格: 题目 一种路径规划算法的改进 ...