55 - 经典问题解析四(动态内存分配虚函数继承中的强制类型转换)
创始人
2024-02-23 21:33:45
0

---- 整理自狄泰软件唐佐林老师课程

1. 关于动态内存分配

new和malloc的区别是什么?
delete和free的区别又是什么?

1.1 问题一:new和malloc的区别

1.1.1 new关键字和malloc函数的区别

new关键字是C++的一部分malloc是由C库函数提供的函数
new以具体 类型 为单位进行内存分配malloc以 字节 为单位进行内存分配
new在申请内存空间时可进行初始化malloc仅根据需要申请定量的内存空间
new在所有C++编译器都被支持malloc在某些系统开发中是不能调用的
new能够触发构造函数的调用malloc仅分配需要的内存空间
对象的创建只能使用newmalloc不适合面向对象开发

1.1.2 编程实验:new和malloc的区别一

下面的代码输出什么?为什么?

在这里插入图片描述

1.1.3 编程实验:new和malloc的区别二

下面的代码输出什么?为什么?

在这里插入图片描述

1.2 问题二:delete和free的区别

delete在所有C++编译器中都被支持free在某些系统开发中是不能调用的
delete能够触发析构函数的调用free仅归还之前分配的内存空间
对象的销毁只能使用deletefree不适合面向对象开发

2. 关于虚函数

2.1 问题一

构造函数是否可以成为虚函数?
析构函数是否可以成为虚函数?

  • 构造函数 不可能 成为虚函数

    在构造函数执行结束后,虚函数表指针才会被正确的初始化

  • 析构函数 可以 成为虚函数

    建议在设计类时将析构函数声明为虚函数

  • 编程实验:构造、析构、虚函数

#include 
#include using namespace std;class Base
{
public:Base(){cout << "Base()" << endl;func();}virtual void func() {cout << "Base::func()" << endl;}virtual ~Base(){func();cout << "~Base()" << endl;}
};class Derived : public Base
{
public:Derived(){cout << "Derived()" << endl;func();}virtual void func(){cout << "Derived::func()" << endl;}~Derived(){func();cout << "~Derived()" << endl;}
};int main()
{Base* p = new Derived();// ...delete p;return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 问题二

构造函数中是否可以发生多态?
析构函数中是否可以发生多态?

  • 构造函数中 不可能 发生多态行为

    在构造函数执行时,虚函数表指针 未被 正确初始化

  • 析构函数中 不可能 发生多态行为

    在析构函数执行时,虚函数表指针 已经被销毁

  • 构造函数和析构函数中调用虚函数不可能发生多态行为,只调用 当前类中 定义的函数版本

在这里插入图片描述

3. 关于继承中的强制类型转换

  • 继承中如何正确的使用强制类型转换?

    • dynamic_cast是与继承相关的类型转换关键字

    • dynamic_cast要求相关的类中必须有虚函数

    • 用于直接或者间接继承关系的指针(引用)之间

      • 指针:
        转换成功:得到目标类型的指针
        转换失败:得到一个 空指针

      • 引用:
        转换成功:得到目标类型的引用
        转换失败:得到一个 异常操作信息

    • 编译器会检查dynamic_cast的使用是否正确

    • 类型转换的结果只可能在 运行阶段 才能得到

  • 编程实验:dynamic_cast的使用

在这里插入图片描述
注解:

#include 
using namespace std;class A {
public:virtual ~A() { cout<<"~A()"<
public:virtual ~B() { cout<<"~B()"<
public:virtual ~C() { cout<<"~C()"<
public:virtual ~D() { cout<<"~D()"<A* pA;B* pB;C* pC;D* pD = new D;pA = dynamic_cast(pD);  //向上转型成功if (pA == NULL){cout<<"Upcasting failed: D* to A*"<cout<<"Upcasting successfully: D* to A*"<(pD);  //向上转型成功if (pB == NULL){cout<<"Upcasting failed: D* to B*"<cout<<"Upcasting successfully: D* to B*"<(pD);  //向上转型成功if (pC == NULL){cout<<"Upcasting failed: D* to C*"<cout<<"Upcasting successfully: D* to C*"<

在这里插入图片描述

#include 
using namespace std;class A {
public:virtual ~A() { cout<<"~A()"<
public:virtual ~B() { cout<<"~B()"<
public:virtual ~C() { cout<<"~C()"<
public:virtual ~D() { cout<<"~D()"<A* pA = new A;B* pB;C* pC;D* pD;pB = dynamic_cast(pA);  //向下转型失败if (pB == NULL){cout<<"Downcasting failed: A* to B*"<cout<<"Downcasting successfully: A* to B*"<(pA);  //向下转型失败if (pC == NULL){cout<<"Downcasting failed: A* to C*"<cout<<"Downcasting successfully: A* to C*"<(pA);  //向下转型失败if (pD == NULL){cout<<"Downcasting failed: A* to D*"<cout<<"Downcasting successfully: A* to D*"<

在这里插入图片描述

  • 上述代码中,类的继承顺序是 A==>B==>C==>D,
    • 当pA是指向A类型的对象时( pA = new A; ),向下转型失败,pA不能转换为B*、C*、D*类型。
    • 当pD是指向D类型的对象时( pD = new D; ),向上转型成功,pD可以转换为A*、B*、D*类型。
    • 原因:因为每个类都会在内存中保存一份类型信息,编译器会将存在继承关系的类的类型信息使用指针“连接”起来,从而形成一个继承链,如下所示。
        当使用 dynamic_cast 对指针进行类型转换时,程序会先找到该指针指向的对象,再根据对象找到当前类(指针指向的对象所属的类)的类型信息,并从此节点开始沿着继承链向上遍历,如果找到了要转化的目标类型,那么说明这种转换是安全的,就能够转换成功,如果没有找到要转换的目标类型,那么说明这种转换存在较大的风险,就不能转换。
      在这里插入图片描述

4. 小结

  • new / delete会触发构造函数或者析构函数的调用
  • 构造函数不能成为虚函数
  • 析构函数可以成为虚函数
  • 构造函数和析构函数中都无法产生多态行为
  • dynamic_cast是与继承相关的专用关键字

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...