C++对象模型剖析(一)

C++对象模型

一、对象模型

  • 简单对象模型

    在简单对象模型中,class member并不存放在object中,在object中存放的是一个指向class member的指针;而class function则是存放一个指向function的函数指针

  • 表格驱动对象模型

    为了对所有class的所有object都有一致的对外表达方式,表格驱动对象模型将所有与member相关的信息抽离出来,放在一个data member table和一个member function table之中,class object本身则存放一个指向这两个表格的指针。

  • C++对象模型

    从简单对象模型派生而来,并对内存空间和存取时间做了优化。

    在该模型中,Nonstatic data members被配置于每一个class object之内, static data members则被存放在个别的class object之外;Static和nonstatic function members也被存放在个别的class object之外;Virtual function则以两个步骤支持:

    • 每个class产生出一堆指向vritual function的指针,放在表格中。这个表格被称为virtual tablevtbl
    • 每个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设定setting和重置resetting都由每一个class的constructor、desturctor和copy assignment运算符自动完成。每个class所关联的type_info object也经由virtual table被指出来,通常放在一个slot中。
    class Point {
    public:
        Point(float xval);
        virtual ~Point();
        
    protected:
        virtual ostream& print(ostream &os) const;
        
        float x;
        static int _Point_count;
    };
    

    在这里插入图片描述

继承

C++支持单继承,也支持多继承。

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

一个derived class在本质上模塑其base class实例的方法

  • 在简单对象模型中,每一个base class可以被derived class object内的一个slot指出,该slot内含base class subobject的地址。这个体制的主要缺点是,因为间接性而导致的空间和存取时间上的额外负担,优点则是class object的大小不会因其base class的改变而受到影响。
  • base table模型。base table被产生出来时,表格中的每一个slot内含一个相关的base table地址,这个跟virtual table内含每一个virtual function一样。每一个class object内含一个bptr,它们会被初始化,指向其base class table。这种策略的缺点是:由于间接性而导致的空间和存取时间上的额外负担,优点则是每一个class object中对于继承都有一致的表现方式:每一个class object都应该在某个固定位置上安放一个base table指针,与base class的大小或个数无关。第二个优点是,无需改变class objects本身,就可以放大、缩小、或更改base class table。
  • c++最初采用的继承模型并不运用任何间接性:base class subobject 的 data members 被直接放置于 derived class object中。这提供了对base class members最紧凑而且最有xiaol 的存取。但缺点是base class members的任何改变,包括增减、移除、改变类型等都使得所有用到该base class或其derived class的object必须重新编译。

对象模型如何影响程序

不同的对象模型会导致“现有的程序代码必须修改”或“必须加入新的程序代码”。

举个例子

// 在class X中定义了一个copy constructor,一个virtual destructor和一个virtual function foo:
X foobar() {
    X xx;
    X *px = new X;
    
    // foo() 是一个 virtual function
    xx.foo();
    px->foo();
    
    delete px;
    return xx;
}

// 这个函数有可能在内部被转换为
void foobar(X& _result)
{
    // 构造 _result
    // _result 用来取代local xx
    _result.X::x();
    
    // 拓展X *ptr = new X;
    px = _new(sizeof(X));
    if (px != 0) px->X::x();
    
    // 扩展xx.foo()但不使用virtual机制
    foo(&result);
    // 扩展px->foo()使用virtual机制
    (*px->vtbl[2])(px);
    
    // 扩展delete px;
    if (px != 0)
    {
        (*px->vtbl[1])(px);	// destructor
        _delete(px);
    }
    
    // 无需使用named return statement
    // 无需摧毁local object xx
    return;
}

对象的差异

c++程序设计模型直接支持三种programming paradigms程序设计范式。

  • 程序模型 procedural model
  • 抽象数据类型模型 abstract data type mode
  • 面向对象模型 object-oriented model

多态

Library_materials thing1;

// class Book : public Library_materials { ... }
Book book;

// thing1 并不是一个book
// book被裁切了sliced
// 但是thing1任然保留了Library_material
thing1 = book;

// 调用的是Library_materials
thing1.check_in();

Library_material& thing2;
thing2 = book;

// 引发的的是Book::check_in()
thing2.check_in();

随让可以直接或间接处理继承体系中的一个base class object,但是只有通过pointer或reference的间接处理,才支持OO程序设计所需的多态性质。

在OO paradigm之中,程序员需要处理一个未知实例,它的类型虽然有所界定,却有无穷可能。这组类型受限于其继承体系,然而该体系理论上没有深度和广度的限制。原则上被指定的object的真实类型在每一个特定执行点之前,是无法解析的。

在C++中,只有通过pointers和reference的操作才能够完成。相反地,在ADT paradigm中,程序员处理的是一个拥有固定而单一类型的实例,它在编译时期就已经完全定义好了。

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

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

    shape *ps = new circle()

  • 仅有virtual function机制

    ps->rotate() 意思是在基类中定义的virtual function在子类中重写,在通过基类指针指向不同的对象时,可以调用不同的方法实例

  • 经由dynamic_casttypeid运算符

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

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

有关dynamic_casttypeid的介绍可以到这篇文章去详细了解一下。

[C++] - dynamic_cast介绍及工作原理、typeid、type_info_dynamic_cast原理-CSDN博客

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

    一般而言要有:

    • nonstatic data members的总和大小

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

      alignment就是将数值调整到某数的倍数。在32位的计算机上,通常alignment为4bytes,以使bus的“运输量”达到最高效率

      这句话的意思就是内存对齐

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

指针的类型the type of a pointer

int *p1;
Array<string> *p2;
ZooAnimal *p3;

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

转换cast之影响”被指出的内存的大小和其内容“的解释方式。

class ZooAnimal {
public:
    ZooAnimal();
    virtual ~ZooAnimal();
    virtual void rotate();
protected:
    int loc;
    String name;
};

class Bear : public ZooAnimal {
public:
    Bear();
    ~Bear();
    void rotate();
    virtual void dance();
protected:
    enum Dances {...};
    
    Dances dances_known;
    int cell_block;
};

Bear b("Yogi");
Bear *pd = &b;
Bear &rb = *pd;

该类的布局

在这里插入图片描述

// 但是如果是通过这种方式来进行的话=
Bear b;
ZooAnimal *pz = &b;
Bear *pd = &b;

它们每个都指向Bear object的第一个bytes。其间的差别是,pd所涵盖的地址包含整个Bear object,而pz所涵盖的地址只包含Bear Object中的ZooAnimal subobject。

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

z = &b;
Bear *pd = &b;

它们每个都指向Bear object的第一个bytes。其间的差别是,pd所涵盖的地址包含整个Bear object,而pz所涵盖的地址只包含Bear Object中的ZooAnimal subobject。

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

引用文献:《深度探索C++对象模型》

  • 11
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 《深度探索C++对象模型》是由侯捷所著的一本经典的C++图书,该书于2012年由机械工业出版社出版。本书的主要内容涵盖了C++对象模型的深入解析和探讨。 在书中,作者详细讲解了C++中的对象模型和相关的概念,如类、对象、继承、多态等。作者首先介绍了C++对象模型的基本概念和特点,包括对象的内存布局、虚函数表和虚函数指针等。然后,作者深入探讨了C++中的继承机制和多态性,包括单继承、多继承、虚继承等。作者还详细介绍了虚函数的实现原理和使用方法。 在书中,作者对C++对象模型的实现细节进行了深入的剖析,包括成员变量和成员函数的内存布局、函数指针和成员函数指针的用法等。同时,作者还讨论了C++中的一些高级特性,如模板、内存管理和异常处理等。通过对C++对象模型的深度探索,读者可以更好地理解C++的内部机制和原理,提高程序设计和开发能力。 《深度探索C++对象模型》适合具有一定的C++编程基础的读者阅读,尤其是对C++对象模型感兴趣的读者。通过阅读本书,读者可以进一步了解C++的底层实现和运行机制,从而提高自己的编程能力和代码质量。此外,本书还提供了大量的示例代码和实践案例,可以帮助读者更好地理解和应用所学知识。 总之,《深度探索C++对象模型》是一本深入探讨C++对象模型的经典著作,通过对C++的底层实现和内部机制的剖析,帮助读者深入理解C++编程语言,并提高自己的软件开发能力。 ### 回答2: 《深度探索C++对象模型》是由Stanley B. Lippman于1994年所著的一本经典畅销的C++书籍,该书详细介绍了C++对象模型的内部实现细节。 C++对象模型是指C++编译器在处理对象、继承、多态等面向对象特性时所采用的具体实现方式。这本书通过对对象模型剖析,帮助读者深入理解C++的内部工作原理,从而写出更高效、更可靠的C++代码。 在《深度探索C++对象模型》中,作者首先介绍了对象、虚函数、继承等C++核心概念,然后详细讲解了C++对象模型的构建过程,包括对象布局、成员函数指针、虚函数表等。作者逐步深入地剖析C++对象模型在内存中的表示方式,解释了为什么C++可以支持如此强大的面向对象特性。 此外,本书还探讨了一些高级主题,如多重继承、虚拟继承、构造函数和析构函数的执行顺序等。对于想要深入学习C++的读者来说,这本书提供了一些宝贵的技术手册和实用的经验。 尽管《深度探索C++对象模型》的出版时间是1994年,但它仍然被广泛认可为学习C++对象模型的经典之作。在2012年时,由于C++的发展和演进,也许一些内容已经有些过时,但很多基本概念和原理仍然适用。 总而言之,《深度探索C++对象模型》是一本值得阅读的C++经典著作,通过深度探索C++对象模型,读者可以更加深入地了解C++的内部工作原理和实现方式,提升自己的开发技能。 ### 回答3: 《深度探索C++对象模型》是一本于2012年出版的书籍。该书的作者Andrews和Sorkin以全面的角度深入探讨了C++对象模型。该书重点介绍了C++中的对象表示、虚函数、继承、多重继承、构造函数、析构函数等内容,以及与之相关的语法、原理和底层实现。 这本书为读者揭示了C++对象模型的奥秘,让人更加深入地理解C++语言中的类和对象。作者通过分析对象布局、虚函数表、虚函数调用、多继承中的数据布局和函数调用等等,解释了C++对象模型的实现机制。 在读者了解C++对象模型的基础上,该书还介绍了如何有效地利用对象模型来提高程序的性能。作者讨论了虚函数的成本以及如何减少虚函数调用的开销,提供了一些优化技巧。此外,书中还对C++的构造函数和析构函数进行了深入的讨论,详细解释了构造函数和析构函数的执行机制和注意事项。 总的来说,《深度探索C++对象模型》是一本深入剖析C++对象模型的重要参考书籍。通过阅读该书,读者可以更加全面地了解C++的类和对象的实现原理,对于理解C++语言的底层机制和优化程序性能具有积极的作用。无论是对于初学者还是有一定C++基础的开发人员来说,该书都是一本值得阅读的重要参考书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值