面向对象高级编程(下)-- 第二周学习笔记(Boolan)

下面简单图示说明使用gcc 4.6在x86 ubuntu上vptr和vtbl(以及VTT)布局。
关于VTT的参考链接:
http://stackoverflow.com/questions/6258559/what-is-the-vtt-for-a-class

根据我自己的验证,得到下面的结论:

  1. x86 ubuntu上char类型为1字节,int为4个字节,double为8个字节,地址对齐方式是4字节对齐
    2)如果一个类没有父类,并且没有虚函数,那么其对象的内存布局就是各个数据成员按定义顺序排列,并对其大小进行4字节对齐后得到的结果。没有vtbl,因而也没有vptr.
    3)如果一个类没有父类,并且有虚函数,其对象开始地址会包含一个指向本类型vtbl中第一个虚函数的指针(vptr),接下来是其各个数据成员。vtbl中前面两项是0以及一个指向其typeinfo的指针,后面是虚函数的地址,而vptr指向自己vtbl中的第一个虚函数地址。
    4)如果一个类是从一个父类public继承,并且父类中没有虚函数,其对象内存布局是其父类的数据成员,后面跟随的是本类的数据成员。因为父类和子类都没有虚函数,所以没有vtbl,因而没有vptr。
    5)如果一个类是从一个父类public继承,并且父类中有虚函数,但是自己没有虚函数。那么其对象内存布局第一个位置是指向本类型vtbl中第一个虚函数的偏移地址的指针。其vtbl中前面两项分别是0和指向自己typeinfo的指针,第三项开始是其虚函数的偏移地址。
    6)如果一个类从父类virtual继承,那么还会生成VTT表(实际上其中包含指向其vtbl偏移地址的指针)。
    7)多重继承的情况下,其内存布局是从基类内存布局依次排列,然后后面跟随自己的虚函数指针(假设有虚函数)和其数据成员。

测试代码如下(主要考察是否有虚函数以及public和virtual继承的差别):

 1 #include <iostream>
 2 
 3 class NoVirtualFunc{
 4  int a;
 5  double b;
 6  char c;
 7 };
 8 
 9 class VirtualFunc{
10  int x;
11  double y;
12  char z;
13 public:
14  virtual void vfunc1(){}
15 };
16 
17 class PublicDerivedFromNoVirtualFunc: public NoVirtualFunc{
18  int pdfnvf;
19 };
20 
21 class PublicDerivedFromVirtualFunc: public VirtualFunc{
22  int pdfvf;
23 };
24 
25 class VirtualDerivedFromNoVirtualFunc: virtual NoVirtualFunc{
26  int vdfnvf;
27 };
28 
29 class VirtualDerivedFromVirtualFunc: virtual VirtualFunc{
30  int vdfvf;
31 };
32 
33 class PublicMultiple: public NoVirtualFunc, public VirtualFunc{
34  int pm;
35 };
36 
37 class VirtualMultiple: virtual  NoVirtualFunc, virtual VirtualFunc{
38  int vm;
39 };
40 
41 class AnotherVirtualFunc{
42  char c;
43 public:
44  virtual void g(){} 
45 };
46 
47 class PublicMultipleTwoVirtual:public VirtualFunc, public AnotherVirtualFunc{
48  char pmtv;
49 };
50 
51 class VirutalMultipleTwoVirtual:virtual VirtualFunc, virtual AnotherVirtualFunc{
52  char vmtv;
53 };
54 
55 int main(void)
56 {
57  NoVirtualFunc o1;
58  VirtualFunc o2;
59  
60  PublicDerivedFromNoVirtualFunc o3;
61  PublicDerivedFromVirtualFunc o4;
62  
63  VirtualDerivedFromNoVirtualFunc o5;
64  VirtualDerivedFromVirtualFunc o6;
65  
66  PublicMultiple o7;
67  VirtualMultiple o8;
68 
69  AnotherVirtualFunc o9;
70  PublicMultipleTwoVirtual o10;
71  VirutalMultipleTwoVirtual o11;
72  
73  return 0;
74 }

const

const成员函数
const可以修饰成员函数来避免成员函数对this指针的修改。
当成员函数的const和non-const版本都存在时,const成员只能调用const版本,
non-const成员只能调用non-const版本。

new&delete

我们可以对operator new和operator delete进行各种版本的重载,但是每个版本都需要有自己的独特参数序列
其中第一个参数必须是size_t.
对于operator delete的各种重载版本,它们虽然可以被重载,但是不会被delete调用,只有当new 调用的构造函数抛出异常时,它们才会被调用,用来清除申请失败对象的内存。
关于operator new和 operator delete的具体讨论见这次作业。operator new与 delete重载

当然我们也可以通过使用域作用符::来强制使用全局new和全局delete,调用方法是::new和::delete

posted on 2018-02-04 23:54  三万八千里  阅读(135)  评论(0编辑  收藏  举报

导航