深度探索C++对象模型笔记 [1] 关于对象

本文主要基于Stanley.B.Lippman的《Inside the C++ Object Model》(侯捷译)而做的一些归纳(文字大多按照译文,进行了适当精简)

前言

在C中,“数据”和“处理数据的操作(函数)”是分开声明的,也就是说,语言本身并没有支持“数据和函数之间”的关联性。这种程序写法称作“程序性的(procedural)”,即所谓面向过程。      

       抽象数据类型(Abstract data type,ADT): 抽象数据类型 = 逻辑结构 + 抽象运算,也就是说抽象数据类型是建立在逻辑结构上的一些抽象的运算,比如C++中的string class,其支持 = ,+等运算。

   数据抽象:用ADT描述程序处理的实体时,强调的是其本质的特征、其所能完成的功能,以及它和外部用户的接口。我们需要注意的是:这里在描述数据时忽略了数据的形态,而是一种数据抽象,且不会涉及到高级程序语言中的具体实现和存储。

   数据封装:将实体的外部特征和内部实现细节分离,并且对外部用户隐藏其内部实现细节(即抽象数据类型内部的各种定义),对于用户来说只需要使用即可,不需要知道内部的具体实现细节。

     加上封装后的布局成本,并没有增加!C++在布局以及存取时间上的主要额外负担是由virtual机制引起的,包括virtual function机制和virtual base class。

 

一、C++对象模式

在C++中,有两种类数据成员,即static(静态成员变量)和nonstatic(非静态成员变量),以及三种类成员函数,static(静态成员函数)、nonstatic(非静态成员函数)、virtual(虚函数)。

简单对象模型最基本的模型,为了尽量减低C++编译器的设计复杂度而开发,赔上空间和运行期效率。此模型中,一个object是一些列的slots,每一个slots指向一个members,members按其声明顺序,各被指定一个slot。每个数据成员或者成员函数都有一个自己的slot。这个模型并未应用于实际产品,但关于索引及slot个数的观念被应用于C++“指向成员的指针”观念中。

表格驱动对象模型:为了对所有类的所有object都有一致的表达形式,这种模型把所有与成员相关的信息抽取出来,放在一个成员函数表和一个成员数据表内。Class object本身则内含指向这两个表格的指针。成员函数表是一系列的slots(槽),每个slots对应一个成员函数,而数据成员表则直接持有数据本身。此模型虽然没有用于真正的C++编译器上,但成员函数表成为了虚函数的一个支持方案。

C++对象模型:最初设计的(目前仍有优势)C++对象模型是从简单对象模型派生来的。并对内存空间和存取时间做了优化。此模型中,nonstatic data members被配置与每一个class object之,static data members则存放在个别的class object 之。static和nonstatic function members也被放在class object之。虚函数则以两个步骤支持之------1、每一个类产生一堆指向虚函数的指针,放在表格中,被称作虚函数表(vtbl) ; 2、每个class object被安插一个指针,指向相关的虚函数表,这个指针被称作vptr。

不同的对象模型,会导致“现有的程序代码必须修改“以及”必须加入新的程序代码“两个结果。

 

二、关键词所带来的差异

这里引入一个问题,什么时候一个人应该实用struct代替class?

实际上,class的真正特性是由声明本身所决定的。

策略性正确的struct:C的设计技巧有时候可能成为C++的陷阱!比如把单一元素的数组放在一个struct的末尾,于是每个struct object可以拥有可变大小的数组:

Struct muble{

Char pc[1]

}

处于同一个access section的数据,必定保证以其声明顺序出现在内存布局中。而放置在多个access section内的数据,排列顺序就不一定了。同理,基类和派生类的数据成员布局也没有谁先谁后的强制规定,因此也不保证前述C的技巧有效。虚函数的存在也会给C的技俩的有效性成为一个问号。所以最好是不那么做!

C struct在C++中的一个合理用途,是当要传递“一个复杂的class object的全部或者部分“到某个C函数时,struct 声明可以将数据封装起来,并保证与C兼容得空间布局。然而这只在复合得情况下才存在。这种做法时,从C struct 中派生C++的部分:

Struct C_point{……};

Class point : public C_pont {…};

 

三、对象的差异

这里列举一些比较常见的范式:函数化程序设计、逻辑程序设计、语意数据模型、几何计算、数值计算、面向对象设计、原型设计、自然语言。

C++程序设计模式直接支持三种程序设计范式(programming paradigms):1.程序模型(procedural model) 2.抽象数据类型模型(abstract data type model) 3.面向对象模型(object-oriented model).

纯粹以一种范式写程序,有助于整体行为的良好稳固,但如果混合了多种范式,可能造成意想不到的结果。比如,虽然可以直接或间接处理继承体系中的一个基类对象,但只有通过指针或引用的间接处理,才能支持面向对象程序设计所需的多态性。在面向对象设计范式中,程序员要处理一个未知实例,它的类型虽然有所界定,却有无穷可能,原则上,被指定的对象的真实类型在每一个特定的执行点前,是无法解析的!在C++中,只有通过指针和引用的操作才能够完成,相反,在ADT范式中,程序员处理的实例是一个拥有固定而单一类型的实例,其在编译期就完全定义好了!

比如:

Librar_materials *px = retrieve_some_material();

Librar_materials &rx = *px;

Librar_materials dx = *px;

在这里,无法确定px或者rx到底指向何种类型的对象,只能说要么是一个Librar_maerials类的对象或者其子类对象,但是,可以确定dx只能是一个Librar_materials对象。

  

C++通过以下方式支持多态:

经由一组隐式转化操作,比如把一个派生类指针转化为一个指向其public base type的指针

Shape *ps = new circle();

 

经由虚函数机制

Ps->rorate();

 

经由dynamic_cast和type_id运算符

If(circle *pc = dynamic_cast<circle *>(ps))…

 

多态的主要用途式经由一个共同接口来影响指针的封装。这个接口通常被定义于一个抽象的基类中。

 

这里,引入一个大家可能比较关注的问题,即需要多少内存才能表现一个class object?一般而言要有:

  1. 其nonstatic data members 的总和大小
  2. 加上任何由于alignment的需求而填补上的空间(alignment就是将数值调整到某数的倍数。在32位机上,通常为4bytes,以使得bus的“运输量”达到最高效率)
  3. 加上为了支持virtual而由内部产生的任何额外负担(一个指针,不管指向任何类型,大小都是固定的)

 

指针的类型:指向不同类型之各指针间的差异,既不在于其指针表示法不同,也不在于其内容(仅存储地址)不同,而是在其所寻址出来的object类型不同,也就是说,指针类型会教导编译器如何解释某个特定地址中的内存内容及其大小

比如,一个指向地址1000的整数指针,其在32位机上,将涵盖地址空间1000~1003(int是4位)。如果String是传统的8-bytes(包括一个4-bytes的字符指针和一个用来表示字符串长度的整数),那么一个ZooAnimal指针将横跨地址空间1000~1015(4位int,8位string,4位虚表指针)。那么,一个类型是void的指向地址1000的指针,将涵盖怎样的地址空间呢?这是未知的,所以这就是为什么一个类型为void的指针只能拥有一个地址,而不同通过这个地址操作所指之object!

加上多态后:现在,定义一个Bear,作为一种ZoomAnimal(假设ZoomAnimal对象大小为16bytes)。

假设Bear object放在地址1000处,那么一个ZoomAnimal的指针与Bear的指针区别是什么呢?---------它们每个都指向Bear Object的第一个byte,差别是,Bear的指针对应的地址涵盖整个Bear object,而ZoomAnimal的指针涵盖范围是Bear Object中的ZoomAnimal subobject(即属于基类的成分,注意,虚表指针也属于基类的成分!)。

但如果不是以指针或者引用的方式来获取Bear object,那么会引发一些问题。

Bear b;

ZoomAnimal za = b;

Za.rotate;    //这里调用的不是bear的rorate而是zoomAnimal的

在这里za也是一个Bear,而是个ZoomAnimal!!!!因为多态并不支持“直接存取object”这事之上(需要使用指针或者引用)。但如果以这样的方式:ZoomAnimal *za =Bear b就可以使用多态了!

一个指针或者一个引用之所以支持多态,是因为它们并不引发内存中任何“与类型有关的内存委托操作”,会受到改变的,只有它们所指向的内存的“大小和内容解释方式”而已。C++通过指针或者引用来支持多态,这种程序设计风格就叫做面向对象

C++也支持具体的ADT程序风格,如今被称为object-based(OB),例如string class就是一种非多态的数据类型。一个OB设计可能比一个对等的OO设计速度更快且空间紧凑。速度快事因为所有的函数调用操作都在编译器完成(一般编译期所完成的工作份额比例越大,速度越快),对象构建起来不需要设置virtual机制;空间紧凑则是因为每一个class object不需要负担传统上为了支持virtual机制而需要的额外负荷,不过OB设计比较缺少弹性。程序设计往往在弹性(OO)和效率(OB)间做抉择。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答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++基础的开发人员来说,该书都是一本值得阅读的重要参考书。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值