守望者--AIR技术交流

标题: C++以多态方式处理数组可能会遇到的问题 [打印本页]

作者: 破晓    时间: 2015-6-3 15:53
标题: C++以多态方式处理数组可能会遇到的问题

今天读《More Effective C++》时遇到一个条款:绝对不要以多态方式处理数组。以前自己也没有注意过,觉得有必要记录下来。


C++是允许通过base class的指针或引用来操作derived class所形成的数组的。但发生的事情可能会令你感到意外。下面举例说明:

基类和派生类是这样的:

  1. class BST                            /*base class*/
  2. {
  3. public:
  4.     BST() : x1(1) {}
  5.     virtual ~BST()
  6.     {
  7.         cout << "Good Bye BST." << endl;
  8.     }
  9.     int x1;
  10. };

  11. class BalancedBST : public BST        /*derived class*/
  12. {
  13. public:
  14.     BalancedBST() : BST(), x2(2) {}
  15.     virtual ~BalancedBST()
  16.     {
  17.         cout << "Good Bye BalancedBST." << endl;
  18.     }
  19.     int x2;
  20. };
复制代码
下面我重载了两个输出操作符:

  1. /*输出base class*/
  2. ostream& operator<<(ostream& os, const BST& obj)        
  3. {
  4.     os << "class BST: " << obj.x1 << endl;
  5.     return os;
  6. }

  7. /*输出derived class*/
  8. ostream& operator<<(ostream& os, const BalancedBST& obj)   
  9. {
  10.     os << "Class BalancedBST: " << obj.x1 << ' ' << obj.x2 << endl;
  11.     return os;
  12. }
复制代码
下面这个函数用于输出base class和derived class的数组。

  1. /*输出base class和derived class数组*/
  2. void Print(ostream& os, const BST arr[], int n)
  3. {
  4.     for (int i = 0; i < n; ++i)
  5.     {
  6.         os << arr[i];
  7.     }
  8. }
复制代码
当以如下方式测试时,没有问题。

  1. BST baseArr[10];
  2. Print(cout, baseArr, 10);    //好的,没问题,正常
复制代码
当以如下方式测试时,就会出现问题。

  1. BalancedBST deriveArr[10];
  2. Print(cout, deriveArr, 10);    //出错啦
复制代码

[attach]1190[/attach]


编译器要想遍历数组中每一个元素,它必须知道每一个元素的大小。很明显,当print参数为BalancedBST数组时,编译器静态的将其数组大小当作BST的大小处理,以*(i+arr)的方式前进,结果是未知的。


还有一种情况,就是通过一个base class指针,删除一个由derived class组成的数组。当以如下方式测试时,没有问题。
  1. BST *base = new BST[10];
  2. delete [] base;                    //好的,没有问题

  3. BalancedBST *derived = new BalancedBST[10];
  4. delete [] derived;                //好的,没有问题
复制代码
当我以如下方式测试时,就会有问题。[attach]1191[/attach]
当数组被删除时,数组中每个元素的destructor会被调用,调用的顺序与构造顺序相反。也就是说执行delete [] base语句时,会产生类似下面的代码。
  1. for (int i = 9; i >= 0; --i)    //编译器产生类似的代码,但是是错误的。
  2. {
  3.     base[i].BST::~BST();
  4. }
复制代码
根本原因还是编译器把derived class数组成员的大小当作base class来计算数组元素的位置。 C++规定,通过base class指针删除一个由derived class objects构成的数组,其结果是未定义的。所以,多态和指针算术不能混用,数组对象几乎总会涉及指针的算术运算,因而数组和多态不要混用。

本文来自:http://www.cnblogs.com/mengwang024/p/4548821.html







欢迎光临 守望者--AIR技术交流 (http://www.airmyth.com/)