1.1 C++对象模型
在C++中,有两种class data members:static和nonstatic,以及三种class member functions:static、nonstatic和virtual。
eg:
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++编译器的设计复杂度较低
缺点:空间和执行期的效率
在这个简单模型中,一个object是一系列的slots,每一个slot指向一个members。Members按其声明顺序,各被指定一个slot。每一个data member或function member都有自己的一个slot。member本身并不放在object中,只有“指向member的指针”才放在object内。这么做可以避免“members有不同的类型,因而需要不同的存储空间”所导致的问题。
表格驱动对象模型
C++对象模型
加上继承
一个derived class如何在本质上模塑其babse class的实例呢?这里有一种所谓的base table模型。这里所说的base class table被产生出来时,表格中的每一个slot内含一个相关的base class地址,这很像virtual table内含每一个virtual function的地址一样。每一个class object内含一个bptr,它会被初始化,指向其base class table。
缺点:
由于间接性而导致的空间和存取时间上的额外负担
优点:
每一个class object中对于继承都有一致的表现形式:每一个class object都应该在某个固定位置上安放一个base table指针,这与base classes的大小或个数无关。
无需改变class objects本身,就可以放大、缩小,或者更改base class table。
1.2关键词所带来的差异
struct关键词与class关键词的区别
1.最本质的一个区别就是默认的访问控制,默认的继承访问权限。struct是public的,class是private的。
2.在观念上,struct关键词是C的数据抽象概念,class关键词是C++的抽象数据类型观念。
策略性正确的struct
C程序员的巧妙设计可能成为C++程序员的陷阱。比如把单一元素的数组放在一个struct的尾端,于是每个struct objects可以拥有可变大小的数组
Struct mumble { Char pc[1]; }; //读取一个字符串,为struct 本身与该字符串配置足够的内存 Struct mumble * pmumbl = (struct mumble *) malloc(sizeof(struct mumble) + strlen(string) + 1); Strcpy(pmumble->pc, string);关于上述程序:
首先,结构体的末尾定义了一个char数组,只分配了1个字符。那怎么能说是可变大小数组。
往下看,他用malloc函数分配了一堆的内存。大小为结构体+字符串+1(字符串结束符)如下图所示。
注意:
1在sizeof struct mumble已经包含了pc[1]的内存。
2pmumb1已经分配了足够的内存,当把string对象拷贝给mumble.pc时,实现了可变大小的数组。通过strcpy,将string字符串拷贝给mumble.pc,pmumble已经分配了足够的内存,因此只要赋值即可,也就达到了
可变大小数组的意思。
但是如果我们改用class来声明,而该class是:
指定多个访问区段,内含数据;
从另一个class派生而来;
定义了一个或多个virtual functions。
那么或许可以顺利转化,但也许不行!这是因为C++凡处于一个access section(访问区段)的数据,必定保证其声明顺序出现在内存布局当中。然而被放置在多个access sections中的各笔数据,排列顺序就不一定了。同理,base classes和derived classes的data members的布局也未有谁先谁后的强制规定,因而也就不保证前述的C伎俩一定有效。
指针的类型
一个指向类的指针是如何与一个指向整数的指针或一个指向template Array的指针有所不同呢
ZooAnimal *px; int *pi; Array<String> *pta;以内存需求的观点来说,没什么不同!它们三个都需要有足够的内存来放置一个机器地址。“指向不同类型之各指针”间的差异,既不在其指针表示法不同,也不在其内容不同,而是在其所寻址出来的obbject类型不同。也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小。
加上多态之后
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 *pb = &b; Bear &rb = *pb;Bear 对象b需要24bytes(我感觉图中少了__vptr__Bear,也就是少了4个字节)。现在假设Bear object放在地址1000处,一个Bear指针和一个ZooAnimal的指针有什么不同呢?
Bear b; ZooAnimal *pz = &b; Bbear *pb = &b;首先介绍一个概念
除了ZoAnimal subobject中出现的members,不能使用pz来直接处理Bear的任何members。唯一的例外是通过virtual机制。