第二版
3.4对象布局第2章讲述了为C编译器而写的一个struct,然后一字不动地用C++编译器进行编译。这里我们就来分析struct的布局,也就是,各自的变量放在内存的什么位置?如果C++编译器改变了C struct中的布局,在C语言代码中如果使用了struct中变量的位置信息的话,那么在C++中就会出错。当我们开始使用一个存取指定符时,我们就已经完全进入了C++的世界,情况开始有所改变。在一个特定的“存取块”(被存取指定符限定的一组声明)内,这些变量在内存中肯定是相邻的,这和C语言中一样,然而这些“存取块”本身可以不按定义的顺序在对象中出现。虽然编译器通常都是按存取块出现的顺序给它们分配内存,但并不是一定要这样,因为部分机器的结构或操作环境可对私有成员和保护成员提供明确的支持,将其放在特定的内存位置上。C++语言的存取指定并不想限制这种好处。存取指定符是struct的一部分,它并不影响从这个struct产生的对象,程序开始运行时,所有的存取指定信息都消失了。存取指定信息通常是在编译期间消失的。在程序运行期间,对象变成了一个存储区域,别无他物,因此,如果有人真的想破坏这些规则并且直接存取内存中的数据,就如在C中所做的那样,那么C++并不能防止他做这种不明智的事,它只是提供给人们一个更容易、更方便的方法。一般说来,程序员写程序时,依赖特定实现的任何东西都是不合适的。如确有必要,这些指定应封装在一个struct之内,这样当环境改变时,他只需修改一个地方就行了。
为了更深入了解C语言与C++在面向对象编程中的差异和具体实现,可以参考以下资源:C语言面向对象编程、C语言的面向对象编程、面向对象C语言。
3.5类存取控制通常是指实现细节的隐藏。将函数包含到一个struct内(封装)来产生一种带数据和操作的数据类型,但由存取控制在该数据类型之内确定边界。这样做的原因有两个:首先是决定哪些用户可以用,哪些用户不能用。我们可以建立内部的数据结构,而用户只能用接口部分的数据,我们不必担心用户会把内部的数据当作接口数据来存取。这就直接导出第二个原因,那就是将具体实现与接口分离开来。如果该结构被用在一系列的程序中,而用户只是对公共的接口发送消息,这样程序员就可以改变所有声明为private的成员而不必去修改用户的代码。封装和实现细节的隐藏能防止一些情况的发生,而这在C语言的struct类型中是做不到的。我们现在已经处在面向对象编程的世界中,在这里,结构就是一个对象的类,就像人们可以描述一个鱼类或一个鸟类,任何属于该类的对象都共享这些特征和行为。也就是说,结构的声明开始描述该类型的所有对象及其行为。
进一步阅读相关内容,请访问这些链接:面向对象C语言课件、C语言面向对象设计、OOP in C C语言实现面向对象编程。