• C++以多态方式处理数组可能会遇到的问题


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

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

    基类和派生类是这样的:

    class BST                            /*base class*/
    {
    public:
        BST() : x1(1) {}
        virtual ~BST()
        {
            cout << "Good Bye BST." << endl;
        }
        int x1;
    };
    
    class BalancedBST : public BST        /*derived class*/
    {
    public:
        BalancedBST() : BST(), x2(2) {} 
        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 = 0; i < n; ++i)
        {
            os << arr[i];
        }
    }

    当以如下方式测试时,没有问题。

    BST baseArr[10];
    Print(cout, baseArr, 10);    //好的,没问题,正常

    当以如下方式测试时,就会出现问题。

    BalancedBST deriveArr[10];
    Print(cout, deriveArr, 10);    //出错啦

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


    还有一种情况,就是通过一个base class指针,删除一个由derived class组成的数组。

    当以如下方式测试时,没有问题。

    BST *base = new BST[10];
    delete [] base;                    //好的,没有问题
    
    BalancedBST *derived = new BalancedBST[10];
    delete [] derived;                //好的,没有问题

    当我以如下方式测试时,就会有问题。

    当数组被删除时,数组中每个元素的destructor会被调用,调用的顺序与构造顺序相反。也就是说执行delete [] base语句时,会产生类似下面的代码。

    for (int i = 9; i >= 0; --i)    //编译器产生类似的代码,但是是错误的。
    {
        base[i].BST::~BST();
    }

    根本原因还是编译器把derived class数组成员的大小当作base class来计算数组元素的位置。

    C++规定,通过base class指针删除一个由derived class objects构成的数组,其结果是未定义的。所以,多态和指针算术不能混用,数组对象几乎总会涉及指针的算术运算,因而数组和多态不要混用。

  • 相关阅读:
    wxpython 文本框TextCtrl
    python py文件转换成exe
    安装NTP到CentOS(YUM)
    安装NFS到CentOS(YUM)
    安装MongoDB到Ubuntu(APT)
    安装MongoDB到CentOS(YUM)
    安装Mailx到CentOS(YUM)
    安装MYSQL到Ubuntu(APT)
    安装MYSQL到CentOS(YUM)
    安装Kubernetes到CentOS(Minikube)
  • 原文地址:https://www.cnblogs.com/mengwang024/p/4548821.html
Copyright © 2020-2023  润新知