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);//传入的是子类对象,存在问题,底层使用了未定义的操作
}

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

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

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

【More Effective C++ 条款3】最好不要以多态方式处理数组的更多相关文章

  1. [More Effective C++]条款22有关返回值优化的验证结果

    (这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...

  2. More Effective C++ 条款0,1

    More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...

  3. Effective C++ 条款08:别让异常逃离析构函数

    1.别让异常逃离析构函数的原因 <Effective C++>第三版中条款08建议不要在析构函数中抛出异常,原因是C++异常机制不能同时处理两个或两个以上的异常.多个异常同时存在的情况下, ...

  4. Effective C++ -----条款28:避免返回handles指向对象内部成分

    避免返回handles(包括reference.指针.迭代器)指向对象内部.遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handle ...

  5. Effective C++ -----条款21:必须返回对象时,别妄想返回其reference

    绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个loc ...

  6. Effective C++ -----条款19:设计class犹如设计type

    Class的设计就是type的设计.在定义一个新type之前,请确定你已经考虑过本条款覆盖的所有讨论主题. 新type的对象应该如何被创建和销毁? 对象的初始化和对象的赋值该有什么样的区别? 新typ ...

  7. Effective C++ -----条款18:让接口容易被正确使用,不易被误用

    好的接口很容易被正确使用,不容易被误用.你应该在你IDE所有接口中努力达成这些性质. “促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容. “阻止误用"的办法包括建立新类型.限 ...

  8. Effective C++:条款27——条款

    条款27:尽量少做转型动作 单一对象可能拥有一个以上的地址!

  9. Effective C++ 条款45

    本节条款的题目是运用成员模板接受全部兼容类型 作者阐述自己的观点是通过智能指针的样例. 在学习本节条款之前我们要先明确关于隐式转化的问题 例如以下代码: #include<iostream> ...

随机推荐

  1. Codeforces 1256A 1257A

    题目链接:https://codeforces.com/problemset/problem/1256/A A. Payment Without Change time limit per test ...

  2. python 检查站点是否可以访问

    最近碰到系统有时候会访问不了,想写一个程序来检测站点是不是可以访问的功能,正好在学python,于是写了一个方法来练练手,直接上代码. import urllib.request import smt ...

  3. 设置 WPF 的全球化语言

    https://stackoverflow.com/questions/7454024/setting-culture-en-in-globally-in-wpf-app Thread.Current ...

  4. 8.了解什么是 redis 的雪崩、穿透和击穿?redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 redis 的穿透?

    作者:中华石杉 面试题 了解什么是 redis 的雪崩.穿透和击穿?redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 redis 的穿透? 面试官心理分析 其实这是问到缓存必问的,因为缓 ...

  5. linux 中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案【转】

    转自:http://blog.chinaunix.net/uid-20768928-id-5077401.html 在LINUX RS485的使用过程中,由于各种原因,最后不得不使用中断底半部机制的方 ...

  6. linux wake on lan功能通过ethtool配置【转】

    转自:https://blog.csdn.net/fanlilei/article/details/38042063 ethtool工具中的wol功能一直很迷惑.今天看了代码将其帮助中下面的参数说明下 ...

  7. Docker容器服务(三)

    一.创建容器 容器是Docker的另一个核心概念. 简单地说,容器是镜像的一个运行实例,所不同的是,它带有额外的可写文件层. 1.1创建一个容器 使用docker create命令创建的容器处于停止状 ...

  8. 使用rider做为unity的代码编辑器

    使用Rider做的编写Unity代码的IDE,记录一些与VS不相同的笔记 安装和设置方法: 我使用Rider 2019.1 + Unity3D 2018.3.4,在安装完Rider之后,在Unity中 ...

  9. Linux sh、source和.命令执行.sh文件的区别

    sh文件介绍 .sh为Linux的脚本文件,我们可以通过.sh执行一些命令,可以理解为windows的.bat批处理文件. 点命令 .命令和source是同一个命令,可以理解为source的缩写,简称 ...

  10. JAVA大数的一些操作

    参考: https://www.cnblogs.com/tonyyy/p/10433460.html https://www.cnblogs.com/wkfvawl/p/9377441.html (d ...