第一章:关于对象(Object Lesson)
1、C++布局成本的增加:Datamember 直接含在每个Class object 之中,但non_inline member function (static和non-static)都在object之外,只有一个函数实体。主要的额外布局负担有Virtual引起。
2、Virtual function 由两步:
一、每个Classs产生一堆指向一个虚函数的指针,放在表格(虚函数表(vtbl))中。
二、每个class object 被添加一个虚函数指针vptr,指向vtbl.同时与每个class相关的type_info object (用以支持RTTI)也在vtbl中被指出来,放在表格的第一个slot处。
3、函数指针,函数重载。声明还是调用:int(*pf)(1024);//调用
Int(*pq)();//声明
4、class的内存布局:C++中处于同一个accesssection 的数据必定保证以其声明的先后顺序放在内存布局中,但是不同的access section 的数据,的排列先后顺序是不一定的。同理,base class 和derived class 的data menbers的布局的先后顺序也是不定的。而C的Struct 则是按声明顺序布局的。注意:class与struct两个关键词是兼容的,语法上是一致的。
5、多态性:(base class) Book A; (derivedclass) a;
Book A=a; A.functon();//是基类方法//此时a假切割,A由B类的基类组件构造而成,是一个“A”,与多态无关
Book &B=a; B.functon();//a的方法。此时B引用a的基类成分。 B是a的基类成分的引用。(指针类似) 要利用多态性,应通过pointer或refrence实现
6、c++,多态只存在于Public继承体系中。其他继承体系没有明白的语言支持多态
7、多态性的具体实现:
一、经由一组隐含的转化操作:派生类向基类的转化(基类指针可接受派生类对象)
二、经由Virtual function 机制:基指针->virtulfunction();
三、经由dynamic_cast 和typied 运算符。
当A类指针指向B类对象时(B派生于A),发生假切割。要知道这个过程只是切掉A类中没有的那些成员,由于vptr是从A类中继承来的,所以这个量仍将保留。而对于vptr的值则不会改变,仍然指向B类的vtable表。所以访问F1函数的时候是通过B类的vtable表去寻址的,自然就是使用子类的函数。(动态联编)
当B类的指针指向A类的对象时(当B类存在新增数据成员时可能出错),同理。
而对于普通函数则受类型的制约,(因为没有vptr指针)使用哪个类的指针调用函数,那么所调用的就是那个类的函数。(静态联编)
总而言之,普通函数通过对象或指针的类型来找所调用的函数,而虚函数是通过一个指针来找到所要调用的函数的。
8、一个Class oblect 需要的内存大小:
其nonstatic data menbers 的总大小 + 由于边界内存管理所需的填补(可能位于member之间,也可能在整体的边界) + 为了支持Vitual的额外负担((有虚函数时有一个指向虚函数表的指针))
注:一个指针不管指向何种类型,其大小是固定的(引用亦同,引用是由指针实现的)
故:一个指向对象的指针或引用都只占一个指针大小的内存!!
9、指向不同类型之各指针,区别只在于对其寻址出来的oblect的类型不同。Void*只含有一个地址,而不能通过它操作其地址。
10、C++通过Class的Pointers和refrence来支持多态,这种程序风格就成为“面向对象“