• 【C++】深度探索C++对象模型读书笔记--关于对象(Object Lessons)


    前言中的内容:

      1.什么是C++对象模型?

        1.语言中直接支持面向对象程序设计的部分

        2. 对于各种支持的底层实现机制

      2. C++ class的完整virtual functions在编译时期就固定下来了,程序员没有办法再执行器动态增加或取代其中一个。这使得虚拟调用操作得以快速地派送结果,付出的成本则是执行期的弹性。

      3. 全局对象在main()函数之前便完成初始化。

    第一章 关于对象

      1. 在C++中,有两种class data members:static 和 nonstatic,以及三种class member functions: static, nonstatic和virtual。

      2. C++对象模型:

        Stroustrup当初设计(目前仍占优势)的C++对象模型是从简单对象模型派生而来的,并对内存空间和存取时间做了优化。在此模型中,Nonstatic data members 被配置于每一个class object之内, static data members则被放在个别的class object之外。Static和nonstatic function members也被放在个别的class object之外。Virtual functions则以两个步骤支持之:

      1. 每一个class产生出一堆指向virtual functions的指针,放在表格之中。这个表格被称为virtual table(vtbl)。

      2. 每一个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设定(setting)和重置(resetting)都由每一个class的constructor,destructor和copy assignment运算符自动完成。每一个clas所关联的type info object(用以支持 runtime type identification,RTTI)也经由virtual table被指出来,通常放在表格的第一个slot。

      这个模型的主要优点在于它的空间和存取时间的效率;主要的缺点是如果应用程序代码本身未曾改变,但所用到的class objects的nonstatic data members有所改变(可能是增加、移除或更改),那么那些应用程序代码同样得重新编译。

      3. C++多态

        简单来说,接口的不同实现方式就是多态。同一操作作用于不同的对象,可以有不同的解释,产生不同的结果。

        在C++,多态只存在于一个个的public class体系中。举个例子,指针px可能指向某个类型的object,或指向根据public继承关系派生而来的一个子类型(请不要把不良的转换操作考虑在内)。Nonpublic的派生行为以及类型为void *的指针可以说是多态的,但它们没有被语言明显地支持,也就是说他们必须由程序员通过显式的转换来管理。

        C++以下列方法支持多态:

        1. 经由一组隐式的转化操作。例如把一个derived class指针转化为一个指向其public class type的指针:

          class circle: public shape{}

          shape *ps = new circle()

        2. 经由virtual function机制:

          ps->func()  或 (*ps).func()

        3. 经由dynamic_cast 和typeid运算符:

          if (circle *pc= dynamic_cast<circle *>(ps))

        在C++中,只有通过基类的指针或引用才能支持OO程序设计所需的多态性质。

      4. 需要多少内存才能够表现一个class object?

        一般而言要有:

        1. 其nonstatic data members的总和大小

        2. 加上任何aligement的需求而填补(padding)上去的空间(可能存在于members 之间,也可能存在于集合体边界)。

        3.加上为了支持virtual而由内部产生的任何额外负担(overhead)

      5. 指针的类型

        一个指针,不管它指向哪一种数据类型,指针本身所需的内存大小是固定的。(32位4B, 64位8B)。“指向不同类型的指针”之间的差异,既不在其指针表示法不同,也不在其内容(代表一个地址)不同,而是在其所寻址出来的object类型不同。也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小。

        一个类型为void*的指针只能够持有一个地址,而不能够通过它操作所指之object。因为不知道它涵盖的地址空间。

        

        加上多态之后:

        现在,我们定义一个Bear,组为一种ZooAnimal,经由“public继承”可以完成这项任务:  

        

     1 class Bear: public ZooAnimal {
     2 public:
     3     Bear();
     4     ~Bear();
     5     //...
     6     void rotate();
     7     virtual void dance();
     8     //...
     9 protected:
    10     enum Dances{...};
    11     
    12     Dance dances_known;
    13     int cell_block;
    14 };
    15 
    16 Bear b("Yogi");
    17 Bear *pb = &b;
    18 Bear &rb = *pb;

      b,pb,rb会有怎样的内存需求呢?不管是pointer或reference都只需要一个word的空间(在32为机器上是4-bytes)。Bear object需要24bytes,也就是ZooAnimal的16 bytes加上Bear所带来的8 bytes。

      好,假设我们的Bear object放在地址1000处,一个Bear指针和一个ZooAnimal指针有何不同?

      Bear b;

      ZooAnimal *pz = &b;

      Bear *pb = &b;

      它们每个都指向Bear object的第一个byte(1000)。其间的差别是,pb所涵盖的地址包含整个Bear Object,而pz所涵盖的地址之包含Bear object中的ZooAnimal subject。

      除了ZooAnimal subject中出现的members,你不能够试用pz来直接处理Bear的任何members。唯一例外是通过virtual机制:

      //不合法:cell_lock不是ZooAnimal的一个member

      //虽然我们知道pz目前指向一个Bear object

      pz->cell_block;

      

      //ok:经过一个显式的downcast操作就没有问题

      (static_cast<Bear *>(pz))->cell_block;

      //下面这样更好,但它是一个run—time operation

      if(Bear* pb2 = dynamic_cast<Bear*>(pz))
        pb2->cell_block;

      

      //ok:因为cell_block是Bear的一个member。

      pb->cell_block;

     扩展阅读:

      1.http://coolshell.cn/articles/9543.html

      

      

  • 相关阅读:
    git命令
    熟悉sql常用语句
    面试:django
    python面试基本题(你需要的)
    django的几种方法进行序列化(视图)
    阿布云代理ip
    了解Git操作
    django前后端交互
    面向对象
    mysql数据库基本操作
  • 原文地址:https://www.cnblogs.com/vincently/p/4644099.html
Copyright © 2020-2023  润新知