[BoolanC++微专业] Week5笔记

一、虚函数和虚表:
上周的学习中学习了虚函数,在学习的时候,我一直有一个疑问,明明在派生类中定义相同名字的函数,就可以覆盖基类的函数,那么virtual的意义是什么呢?就单纯的显式表明这个函数在将来会被派生类的函数给override?实际上并不是这样,虚函数是实现多态的重要步骤下面给一个程序:

class fruit
{
public:
    void func()
    {
        cout << "Fruit" <<endl;
    }
    virtual void vfunc()
    {
        cout << "virtual Fruit" << endl;
    }
};

class apple:public fruit
{
public:
    void func()
    {
        cout<< "Apple" <<endl;
    }
    void vfunc()
    {
        cout << "Virtual Apple" <<endl;
    }
};

int main(int argc, char* argv[])
{
    fruit* f = new apple(); 
    f->func();
    f->vfunc();
    return 0;
}

最后输出的结果是

Fruit
Virtual Apple

这就牵涉到静态绑定和动态绑定的问题,当我们使用存在继承关系的类型时,必须将一个变量或者其他表达式的静态类型与该表达式表示对象的动态类型区分开来。表达式的静态类型在编译时总是已知的,它是变量声明时的类型表达式生成的类型,动态类型是变量或者表达式表示的内存中的对象的类型,动态类型直到运行时才可知。
以上面的程序为例:
因为func()并没有被声明为虚函数。所以在调用f->func()时候,它虽然指向的是一个apple类的内存快,但是f的类型还是 fruit*,所以调用的是 fruit类中的func()。
而vfunc()调用的时候,它使用的便是class中的vtbl(虚表)中动态指向的函数Apple::vfunc()。
需要注意的是,动态绑定只有我们通过指针或者引用调用虚函数才会发生。

OOP的核心思想便是多态性,我们把具有继承关系的多个类型称为多态类型,因为我们能使用这些内容的多种形式,而无需在意他们的差异。引用或者指针的静态类型与动态类型不同这一事实正是C++语言支持多态性的根本所在。
当我们使用基类的引用或者指针调用基类i定义中的一个函数时,我们并不知道该函数真正作用的对象是什么类型,因为它可能是一个基类对象也可能是一个派生类对象,如果该函数是虚函数,则直到运行时才会决定到底执行哪个版本,判断的依据是引用或者指针绑定的对象的真实类型。
另一方面,对非虚函数的调用在编译时进行绑定,类似的,同过对象进行的函数调用也在编译时进行绑定。

这里写图片描述

虚函数的调用,用c代码来实现的话,就是上图中这一句:

(*(p->vptr)[n])(p);
(* p->vptr[n] )(p);

另附上侯捷老师的动态绑定汇编代码:
这里写图片描述

这里写图片描述

二、重载new和delete:
首先我们来分析一下 new和delete的工作机制。
new:
第一步,调用一个名为operator new 或者 operator new[]的标准库函数。
第二部,编译器运行相应的构造函数以构造这些对象,并传入初始值。
第三步,对象被分配了空间并构造完成,返回一个指向该对象的指针。
delete:
第一步,对指针所指向的对象或者指针所指向的数组中的元素执行对应的析构函数。
第二部,编译器调用operator delete或者operator delete[]的标准库函数释放空间。

如果希望控制内存分配过程,则它们需要定义自己的operator new和operator delete函数。编译器并不会对 这种重复的定义提出异议,反而会用我们的版本替换标准库定义的版本。

operator new和operator delete可以定义在类内也可以定义在全局作用域内,在使用时优先在类内搜索new和delete重载。但是我们可以使用::new和::delete来使用全局作用域内的重载函数。

标准库一共有8个delete和new的版本,在这里我们讨论其中4个:

void *operator new(size_t);
void *operator new[](size_t);
void operator delete(void *) noexcept;
void operator delete[](void *) noexcept;

我们可以重载上述函数的任意一个,当我们将上述运算符函数定义成类的成员时,它们是隐式静态的。
因为new作用在对象构造之前,而delete作用在对象析构之后。

我们可以自定义具有任何形参的operator new,但是有一个函数无论如何不可以被用户重载:

void *operator new(size_t,void*);

下面是一个简单的delete和new的重载:

void *operator new(size_t size)
{
    if(void *mem = malloc(size))
    {
        return mem;
    }else
    {
        throw bad_alloc();
    }
}

void operator delete(void *mem) noexcept
{
    free(mem);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值