美文网首页
C++面向对象程序设计(下)第二周学习笔记——Boolan

C++面向对象程序设计(下)第二周学习笔记——Boolan

作者: GINNYAK | 来源:发表于2017-08-14 14:39 被阅读0次

    在完成了C++面向对象高级编程(下)第二周的学习之后,有一些总结和心得在这里通过学习笔记的方式分享出来,笔记我是跟着老师在视频中所讲的内容按照顺序记录的,也不能说是流水账,对课程中的一些问题还是添加了自己的理解和分析,供也在学习C++的小伙伴用作学习交流,如有理解不到位的地方,欢迎批评指正。

    本周主要学习的内容是C++的对象模型,通过对于对象模型的深入学习,了解了虚函数、多态、this指针,以及增加了new、delete部分的详细介绍。

    一.对象模型(Object Model)

    当我们创建出继承关系如上图的A类型、B类型、C类型的对象a、b、c时,它们的对象模型如下图:

    我们发现,对象中占空间的不仅仅是一些类中所声明的成员,还包括了虚函数的指针(vptr),一个类中只要有虚函数而无论有多少个,虚函数指针的个数始终为1个;虚函数指向的是虚函数的地址;一个类中可能会出现多个虚函数,所以这些地址会统一存放在一个列表中,称作虚表(vtbl);图中还可以看到,没有重写的虚函数都指向同一个地址。

    1.动态绑定(Dynamic Binding)

    动态绑定是将一个过程调用与相应代码链接起来的行为。是指与给定的过程调用相关联的代码,只有在运行期才可知的一种绑定,它是多态实现的具体形式。

    C++中,通过基类的引用或指针调用虚函数时,发生动态绑定。引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指对象的实际类型所定义的。

    C++中动态绑定是通过虚函数实现的。而虚函数是通过一张虚函数表(virtual table)实现的。这个表中记录了虚函数的地址,解决继承、覆盖的问题,保证动态绑定时能够根据对象的实际类型调用正确的函数。

    在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

    我们创造一个容器,里面装的是指针;这些指针全部都是经过了向上转型后的对象;(类型都是指向A类的指针);A*类型的变量,会根据指向不同的类(基类或子类)的实例,根据vptr指向的对应函数地址,执行不同的函数,从而实现多态。

    所以,虚函数加上继承是实现多态的手段。动态绑定必须满足以下三个条件:

    必须通过指针调用函数;

    指针必须是向上转型;

    调用的函数必须是虚函数。

    2.关于this指针

    按照灰色箭头的路径:在右边的main函数中,先创建一个子类的对象myDoc,然后子类的对象调用的是父类的函数,通过对象调用一个函数,那么这个对象的地址就是this Pointer;所以这条语句可以写成底下那种形式(&myDoc就是this Pointer)。这个时候,既然调用的是父类的函数,其实就已经是向上转型了。进入函数后,再执行到虚函数Serialize()的时候,调用函数的方式就入图中左上角所示。其中n是虚函数在虚表中的位置。

    二.关于const

    当成员函数的const和non-const版本同时存在时,const object只能调用const版本,non-const object只能调用non-const版本。注意,const是算作函数签名的一部分的。

    上表描述了何时使用member function和object在分别为const和non-const时的关系。

    关键字const在程序中起着至关重要的作用,往往在决定一个函数的功能时就可以考虑要不要在返回类型前加上const了。非成员函数的关键字const添加在函数名前;类中的成员函数添加const的位置如下述代码所示:

    如果当初设计string::print()时未指明const,那么上行便是经由const object调用non-const

    member function,编译器会报错:

    三.关于new和delete

    之前的课程也有学习过,new是先分配memory,再调用ctor;delete是先调用dtor,再释放memory。

    其中operator new分为全局的和属于某个类的区分。可以通过重载operator new(operator new[])或operator delete(operator delete[])函数来自己控制内存的管理。

    重载::operator new是一件危险的事情,因为重载的是全局函数,这可能导致程序中以后每一个new的动作都会调用你自己写的operator new,这样分配空间是不确定的。同样,重载::operator delete也一样,只不过两者传入的参数不同;前者传入的是size_t类型,表示要被分配的空间,后者传入的是一个指针,表示要释放的地址。

    可以在类中去重载new和delete,这样做只针对这个类使用自定义的内存管理:

    使用new或delete时可以指定使用全局的operator new或operator delete函数:

    我们可以重载class member operator new(),写出多个版本,但前提是每一个版本的声明都必须有独特的参数列,即多参数。比如:

    Foo* pf = new(300,’c’)Foo;

    第一参数必须是size_t,其余参数以new所指定的placement arguments为初值,出现于new(…)小括号内的便是所谓的placement arguments.

    我们也可以重载class member operator delete(),写出多个版本。但它们绝不会被delete调用,只有当new所调用的ctor抛出exception时,才会调用这些重载版本的operator delete()。

    ����� %

    相关文章

      网友评论

          本文标题:C++面向对象程序设计(下)第二周学习笔记——Boolan

          本文链接:https://www.haomeiwen.com/subject/xksurxtx.html