zoukankan      html  css  js  c++  java
  • 【More Effective C++ 条款3】最好不要以多态方式处理数组

    1.在数组与多态混用的情况下,数组元素的访问会出现不可预期的结果(因为数组元素的访问会使用到下标运算)

    将一个子类对象数组传递给一个父类对象数组声明的函数,编译器会允许这个行为,但是由于子类对象和父类对象的内存结构不同,会导致运行结果异常,因为在这种情况下,编译器仍然假设每一个元素的大小是父类对象元素的大小,但此时实际上每一个元素的大小是子类对象元素的大小

    #include<bits/stdc++.h>
    using namespace std;
    
    class BST
    {
    public:
        char c;
    };
    
    class balancedBST:public BST//公有继承
    {
    public:
        int x;
    };
    
    void printBSTArray(ostream& s,const BST array[],int numElements)//打印基类数组,注意数组的类型为基类!
    {
        for(int i=0;i<numElements;i++)
            s<<array[i].c;
        s<<endl;
    }
    
    int main()
    {
        BST array[3];
        for(int i=0;i<3;i++)
            array[i].c='A'+i;
    
        printBSTArray(cout,array,3);//传递进入函数的是基类数组,打印正常
    
        balancedBST barray[3];
        for(int i=0;i<3;i++)
        {
            barray[i].x=i+1;
            barray[i].c='a'+i;
        }
    
        printBSTArray(cout,barray,3);//传递进入函数的是子类数组,打印异常!
        /*
        异常的原因:
        因为函数定义的时候该对象的数组定义的是为基类类型,所以编译器在后续的操作中,
        无论传入函数的是基类对象数组还是子类对象数组,都将视为基类对象数组
        而基类对象的内存结构和子类对象的内存结构是不一样的
        这样,通过下标访问到的东西,其实不是你想访问的东西
    
        array[i] *(array+i)
        array[0]和array[i] 之间相隔 i*sizeof(BST)
    
        函数是按照i*sizeof(BST)算的,而如果你传入的是基类对象数组,也按照这样算的话,肯定是访问不到你想要的东西的
        */
    
    
    }
    
    /*
    运行结果:
    ABC
    ai
    */

    2.在多态与数组混用的情况下,数组元素的删除也存在问题,会使用到没有定义的操作(通过基类指针来删除子类对象数组的行为在C++中是未定义的!)

    #include<bits/stdc++.h>
    using namespace std;
    
    class BST
    {
    public:
        char c;
    };
    
    class balancedBST:public BST//公有继承
    {
    public:
        int x;
    };
    
    void deleteArray(ostream& logStream,BST array[])
    {
        logStream<<"Deleting array at adress: "<<static_cast<void*>(array)<<endl;
        delete [] array;//该操作的底层其实使用了下标,如果传入的是子类对象数组,那么通过基类指针来删除子类对象数组的行为在C++中是未定义的!
    }
    
    int main()
    {
        BST *array =new BST[3];
        balancedBST *barray =new balancedBST[3];
    
        deleteArray(cout,array);//传入的是基类对象
    
        deleteArray(cout,barray);//传入的是子类对象,存在问题,底层使用了未定义的操作
    }


    总结:那么如何避免上述两种问题呢?

    第一个办法是避免采用多态方式来处理数组

    第二个方法是避免让一共具体类继承自另外一个具体类



  • 相关阅读:
    Moodle的安装和登陆(使用Https)
    Moodle 3.4中添加小组、大组、群
    【转】moodle中年级、班级、小组研讨
    函数式接口
    java实现数据库连接池
    转载---jboss简单使用
    转载---数据库优化方案
    转载---虚拟机类加载机制
    java中的hashcode
    父子类静态代码块,非静态代码块,有参,无参构造方法等的执行顺序问题
  • 原文地址:https://www.cnblogs.com/yinbiao/p/11747782.html
Copyright © 2011-2022 走看看