zoukankan      html  css  js  c++  java
  • 深入探索C++对象模型(一)

    再读《深入探索C++对象模型》笔记。

    关于对象

    C++在加入封装后(只含有数据成员和普通成员函数)的布局成本增加了多少?

    • 答案是并没有增加布局成本。就像C struct一样,memeber functions虽然含在class的声明之内,却不出现在object中。每一个non-inline member function只会诞生一个函数实体。至于每一个“拥有零个或一个定义的” inline function则会在其每一个使用者(模块)身上产生一个函数实体。

    C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括:

    • virtual funciton机制,用以支持一个有效率的“执行期绑定”(runtime binding)
    • virtual base class,用以实现“多次出现在继承体系中的base class,有一个单一而被共享的实体”

    C++ 对象模式(The C++ Object Model)

    在C++中,有两种class data members:static 和 nonstatic,以及三种class member functions:static、nonstatic和virtual。已知下面这个class Point声明:

    class Point{
    public:
        Point(float xval);
        virtual ~Point();
        float x() const;
        static int PointCount();
    
    protected:
        virtual ostream& print(ostream &os) const;
        float _x;
        static int _point_count;
    };
    

    C++对象模型中,nonstatic data members被配置于每一个class object之内,static data members则被存放在所有的class object之外。static和nonstatic function members也被放在所有的class object之外。virtual function则以两个步骤支持之:
    1. 每个class产生出一堆指向virtual functions的指针,放在表格之中。这个表格被称为virtual table(vtbl)
    2. 每一个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设定和重置都由每一个class的constructor、destructor和copy assignment运算符自动完成。每一个class所关联的type_info object(用以支持runtime type identification, RTTI)也经由virtual table被指出来,通常放在表格的第一个slot处

    故上面的声明所对应的对象模型如下:

    上图说明了C++对象模型如何应用于Point Class身上,这个模型的主要优点在于它的空间和存取时间的效率。主要缺点是:如果应用程序代码未曾改变,但所用到的class objects的nonstatic data members有所修改(有可能是增加、移除或更改),那么应用程序代码同样得重新编译。

    继承关系可以指定为虚拟(virtual,也就是共享的意思):在虚拟继承的情况下,base class不管在继承链中被派生(derived)多少次,永远只会存在一个实例(称为subobject)。

    class istream : virtual public ios{ ... };
    class ostream : virtual public ios{ ... };
    

    对象的差异

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

    • 经由一组隐式的转化操作。例如把一个derived class指针转化为一个指向其public base type的指针
    • 经由virtual function机制
    • 经由dynamic_cast和typeid运算符

    多态的主要用途是经由一个共同的接口来影响类型的封装,这个接口通常被定义在一个抽象的base class中。这个共享接口是以virtual function机制引发的,它可以在执行期根据object的真正类型解析出到底是哪一个函数实体被调用。

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

    • 其nonstatic data members的总和大小
    • 加上任何由于aliginment的需求而填补上去的空间(可能存在于members之间,也可能存在于集合体边界)
    • 加上为了支持virtual而由内部产生的任何额外负担

    一个指针(引用),不管它指向哪一种数据结构,指针本身所需的内存大小是固定的。

    举例如下:一个指向ZooAnimal的指针是如何地与一个指向整数得指针或一个指向template Array的指针有所不同的呢?

    ZooAnimal *px;
    int *pi;
    Array<string> *pta;
    

    以内存需求的观点来说,没有什么不同!它们三个都需要足够的内存来放置一个机器地址(通常是个word)。“指向不同类型的各指针”间的差异,既不在其指针表示法不同,也不在其内容(代表一个地址)不同,而是在其所寻址出来的object类型不同,也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小。

    转型(cast)其实是一种编译器指令。大部分情况下它并不改变一个指针所含的真正地址,它只影响“被指出之内存大大小和其内容”的解释方式。

    当一个base class object被直接初始化为(或被指定为)一个derived class object时,derived object就会被切割(sliced)以塞入较小的base type内存中,derived type将没有留下任何蛛丝马迹。多态于是不再呈现,而一个严格的编译器可以在编译器解析一个“通过此object而触发的virtual function调用操作”,因而回避virtual机制。如果virtual function被定义为inline,则更有效率上的大收获。

  • 相关阅读:
    Spring(十一):Spring配置Bean(四)SpEL
    Java中动态代理方式(使用java.lang.reflect.Proxy实现):
    设计模式(八)静态代理与动态代理模式
    Spring(十):Spring配置Bean(三)Bean的作用域、使用外部属性文件
    如何把本地代码提交到git(码云)、github代码管理项目上
    Spring(九):Spring配置Bean(二)自动装配的模式、Bean之间的关系
    centos7安装mysql5.7
    haproxy(单机)+mysql集群负载均衡
    sql server 用户创建与权限管理
    MySQL之 从复制延迟问题排查
  • 原文地址:https://www.cnblogs.com/lengender-12/p/6944042.html
Copyright © 2011-2022 走看看