• c++对象模型研究1:关于对象


     对象模型

    和c不同,c是将数据和处理数据的函数分开的(数据流过程决定函数编写,过程式的);而c++把数据和处理数据的方法关联在了一起(对象发起动作,操纵数据)。那么像class一样将数据和方法包含在一起,甚至再用上模板是否会增加布局成本呢?

    C++对象模式

    在C++中,有两种类成员数据:static非static,以及三种类成员函数:static非staticvirtual

    在C++对象模型中,非static成员数据被配置于每一个类对象之内,static成员数据则被放在所有类对象之外。static和非static成员函数也被放在所有的类对象之外。

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

    1.虚函数机制(执行时绑定)

    2.虚基类。还有一些多重继承下的额外负担。

    virtual函数则以两个步骤支持之:

    1.每一个类产生出一堆指向virtual函数的指针,放在表格之中。这个表格被称为virtual表。

    2.第一个类对象被添加了一个指针,指向相关的virtual表。这个指针的设定和重置都由每一个类的构造函数,析构函数和拷贝赋值运算符自动完成。另外,虚函数表地址的前面设置了一个指向type_info的指针,RTTI(Run Time Type Identification)运行时类型识别是有编译器在编译器生成的特殊类型信息,包括对象继承关系,对象本身的描述,RTTI是为多态而生成的信息,所以只有具有虚函数的对象在会生成。

    和c相比,c++的布局成本主要来自于virtual,virtual使得class object需要先找虚表,再由虚表找所在地,增加了耗费。而像nonstatic data menber,跟c中struct完全一样,所以这些并不会增加c++的布局成本(相对于c而言)。

    对于C++中的单继承

    C++实际模型是:对于一般继承是扩充已有存在的虚函数表;对于虚继承添加一个虚函数表指针。

    对于C++中的多继承

    1)每一个基类都有自己的虚函数表,基类各有虚表

    2)子类的虚函数被放到第一个基类的虚函数表中,子类与第一个父类共用一张虚表

    3)内存布局中,基类的排列顺序就是基类的声明顺序

    4)重写:每一个基类的虚表中的fun都被重写成子类的fun,这样做就是为了解决不同的基类类型的指针指向同一个子类实例,而能够调用到实际的函数。

    对于C++中的多继承中的虚继承

    虚继承的子类,有单独的虚函数表,另外也单独保存一份父类的虚函数表。

    如何访问成员?

    数据成员如何访问(直接取址)?

    跟实际对象模型相关联,根据对象起始地址+偏移量取得。

    函数成员如何访问(间接取址)?

    跟实际对象模型相关联,普通函数(nonstatic、static)根据编译、链接的结果直接获取函数地址;如果是虚函数根据对象模型,取出对于虚函数地址,然后在虚函数表中查找函数地址。

    多态如何实现?

    多态(Polymorphisn)在C++中是通过虚函数实现的。如果类中有虚函数,编译器就会自动生成一个虚函数表,对象中包含一个指向虚函数表的指针。能够实现多态的关键在于:虚函数是允许被派生类重写的,在虚函数表中,派生类函数对覆盖(override)基类函数。除此之外,还必须通过指针或引用调用方法才行,将派生类对象赋给基类对象。

    为什么析构函数设为虚函数是必要的?

    这个写在《改善程序与设计的具体做法(C++)》中的条款7中。

    ps:

    本质上一个引用通常是以一个指针来实现,而且是const指针。

    参考:

    《深度探索C++对象模型》

    C++对象模型

  • 相关阅读:
    Linux下安装Apache2.4.43踩坑记录
    网络代理条件下配置git
    docker存储驱动的选择
    Python列表排序
    解决apache无法启动No space left on device
    Flask匹配url使用正则表达式
    Web安全-客户端脚本安全
    springboot中的一些好用注解
    基于cdn方式的vue+element-ui的单页面架构
    干货网站
  • 原文地址:https://www.cnblogs.com/losophy/p/9494632.html
Copyright © 2020-2023  润新知