第五十五课、经典问题解析四

一、new和malloc、delete和free之间的区别

1、new和malloc

(1)、new关键字是c++的一部分

            malloc是c库提供的函数

(2)、new是以具体类型为单位分配内存

            malloc是以字节为单位分配内存

(3)、new在申请内存空间时可进行初始化

    malloc仅根据需要申请定量的内存空间

(4)、new在所有c++编译器中都被支持

            malloc在某些系统开发中是不能调用的

(5)、new能触发构造函数的调用

     malloc仅分配需要的内存空间

(6)、对象的创建只能用new

       malloc不适合面向对象的开发

2、delete和free

(1)、delete在所有c++编译器中都被支持

            free在某些系统开发中是不能调用的

(2)、delete能触发析构函数的调用

           free仅归还之前分配的内存空间

(3)、对象的销毁只能用delete

     free不适合面向对象的开发

 

#include<iostream>
#include<cstdlib>//说明malloc和free是函数

using namespace std;

class Test
{
private:
    int *mp;
public:
    Test()
    {
        mp = new int(100);
        cout << "Test()" << endl;
        cout << *mp << endl;
    }

    ~Test()
    {
        delete mp;
        cout << "~Test()" << endl;
    }
};

int main()
{
    Test* t1 = new Test();//会调用构造函数,不能用free来释放,否则可能造成内存泄漏
    Test* t2 = (Test *)malloc(sizeof(Test));//只分配需要的内存空间,不会调用构造函数,不能用delete释放,否则会将mp指针错误释放掉

delete t1;//调用析构函数
    free(t2);//不会调用析构函数
    return 0;
}

二、构造函数、析构函数、虚函数、多态

1、构造函数不可以成为虚函数

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

2、析构函数可以成为虚函数

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

3、构造函数里面不可能发生多态行为

(1)、构造函数执行时,虚函数表指针未被正确初始化

4、析构函数里面不可能发生多态行为

(1)、在析构函数执行时,虚函数表指针已被销毁

 

#include<iostream>

using namespace std;

class Base
{
public:
    Base()// error, can not be declared virtual
    {
        cout << "Base()" << endl;
        func();//不会发生多态,调用当前类里面的func()
    }

    virtual void func()
    {
        cout << "Base::func()" << endl;
    }

    virtual ~Base()//can be declared virtual
    {
        cout << "~Base()" << endl;
        func();//只调用当前类定义的版本
    }
};

class Derived : public Base
{
public:
    Derived()
    {
        cout << "Derived()" << endl;
        func();
    }
    virtual void func()
    {
        cout << "Derived::func()" << endl;
    }
    virtual ~Derived()
    {
        cout << "~Derived()" << endl;
        func();
    }
};

int main()
{
    Base* p = new Derived();//赋值兼容性原则

    cout << endl;

    delete p;//若析构函数不是虚函数,则这里就会只调用父类的构造函数,而不调用子类的,会造成内存泄漏       //根据析构顺序,会先调用父类析构函数,然后调用子类析构函数
    return 0;
}

//打印结果
/*
Base()
Base::func()
Derived()
Derived::func()

~Derived()
Derived::func()
~Base()
Base::func()
*/

三、继承中的强制类型转换

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

2、dynamic_cast要求相关类中必须有虚函数

3、用于有直接或间接继承关系的指针(引用)之间

(1)、指针

A、转换成功:得到目标类型的指针

B、转换失败:得到一个空指针

(2)、引用

A、转换成功:得到目标类型的引用

B、转换失败:得到一个异常操作信息

 

#include<iostream>

using namespace std;

class Base
{
public:
    Base()
    {
        cout << "Base()" << endl;
    }

     virtual ~Base()//使用dynamic_cast需要类中有虚函数,故这里将析构函数声明为虚函数
    {
        cout << "~Base()" << endl;
    }
};

class Derived : public Base
{
};

int main()
{
    Base* p = new Base();

    Derived* d = dynamic_cast<Derived*>(p);//dynamic_cast 可以将子类转换转换成父类,反之不行(子类中可能有新成员),可以判断父子关系

   // Derived* p = new Derived();
    //Base* d = dynamic_cast<Base*> (p);//这样就会转换成功,输出succefully

    if(d != NULL)
    {
        cout << "succefully!" << endl;
    }
    else
    {
        cout << "error" << endl;//结果会输出这个,说明转换失败
    }

    cout << endl;

    delete p;
    return 0;
}

四、小结

(1)、new/delete会触发构造函数或者析构函数的调用

(2)、构造函数不能成为虚函数

(3)、析构函数可以成为虚函数

(4)、构造函数和析构函数里面都不能产生多态的行为

(5)、dynamic_cast 关键字是与继承相关

时间: 2024-12-15 16:35:55

第五十五课、经典问题解析四的相关文章

第三百五十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy信号详解

第三百五十五节,Python分布式爬虫打造搜索引擎Scrapy精讲-scrapy信号详解 信号一般使用信号分发器dispatcher.connect(),来设置信号,和信号触发函数,当捕获到信号时执行一个函数 dispatcher.connect()信号分发器,第一个参数信号触发函数,第二个参数是触发信号, signals.engine_started当Scrapy引擎启动爬取时发送该信号.该信号支持返回deferreds.signals.engine_stopped当Scrapy引擎停止时发送

QT开发(五十五)———Qt Quick Controls

QT开发(五十五)---Qt Quick Controls 一.Qt Quick Controls基础 QT5.1发布了Qt Quick的一个全新模块:Qt Quick Controls.Qt Quick Controls模块提供了大量类似Qt Widgets模块的可重用组件. 为了开发基于Qt Quick Controls的程序,需要创建一个Qt Quick Application类型的应用程序,选择组件集的时候注意选择Qt Quick Controls. 二.Qt Quick Control

“全栈2019”Java第五十五章:方法的静态绑定与动态绑定

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第五十五章:方法的静态绑定与动态绑定 下一章 "全栈2019"Java第五十六章:多态与字段详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组&q

经典问题解析五(五十五)

在面试中有可能会遇到这个面试题,编写程序判断一个变量是不是指针.我们咋一看是不是有点懵逼,我们可以想到利用 C 语言中的可变参数函数.在 C++ 中依然是支持的,C++ 编译器的匹配调用优先级是:1.重载函数:2.函数模板:3.变参函数.我们可以将变量分为两类:指针和非指针.需要编写函数的功能是当是指针变量调用时便返回 true,是非指针变量调用时返回 false. 下来我们就来试着编写下这个函数 #include <iostream> #include <string> usin

第67课 经典问题解析五

1. 指针的判别 (1)拾遗 ①C++中仍然支持C语言中的可变参数函数 ②C++编译器的匹配调用优先级:重载函数>函数模板>变参函数 (2)思路 ①将变量分为两类:指针 VS 非指针 ②编写函数: 指针变量调用时回true 非指针变量调用时返回false (3)函数模板与变参函数的化学反应 template<typename T> //优先匹配函数模板 bool IsPtr(T* v) // match pointer { return true; } //变参函数 //再匹配变参

JAVA学习第五十九课 — 网络编程概述

网络模型 OSI(Open System Interconnection)开放系统互连:參考模型 TCP/IP 网络通讯要素 IP地址 port号 传输协议 网络參考模型 七层OSI模型的基本概念要了解 网际层协议:包含:IP协议.ICMP协议.ARP协议.RARP协议. 传输层协议:TCP协议.UDP协议. 应用层协议:FTP.Telnet.SMTP.HTTP.RIP.NFS.DNS. 要真正实现网络通讯,首先要找到IP地址,IP地址是网络通讯的一大要素 IP地址:InetAddress 网络

第五十八课、自定义模型类(上)------------------狄泰软件学院

 一.自定义模型类 1.QStandardItemModel是一个通用的模型类 (1).能够以任意的方式组织数据(线程.非线性) (2).数据组织的基本单位为数据项(QStandardItem) (3).每一个数据项能够存储多个具体数据(附加数据角色) (4).每一个数据项能够对数据状态进行控制(可编辑.可选...) 2.Qt中的通用模型类QStandardItemModel (1).QStandardItemModel继承自抽象的模型类QAbstractItemModel (2).QStand

JAVA学习第五十二课 — IO流(六)File对象

File类 用来给文件或者文件夹封装成对象 方便对文件与文件夹的属性信息进行操作 File对象可以作为参数传递给流的构造函数 一.构造函数和分隔符 public static void FileDemo() {//构造函数演示 //可以将一个已存在或不存在的文件或目录封装成File对象 File file = new File("d:\\a.txt"); File file2 = new File("d:","a.txt"); File file

JAVA学习第五十五课 — IO流(九)文件切割合成器

文件切割器 private static final int SIZE = 1024 *1024; public static void splitFile(File file) throws IOException{ //用读取流关联文件(不确定文件格式) FileInputStream fis = new FileInputStream(file);//源是一个 byte[] by = new byte[SIZE];//定义1M的缓冲区 FileOutputStream fos = null