`
zaf727hc
  • 浏览: 11858 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

读书笔记 《深度探索c++对象模型》 (4)

 
阅读更多

读书笔记 《深度探索c++对象模型》 (4)
2010年07月04日
  第五章:构造,解构,拷贝语意学
  5.2 继承体系下的对象构造
  a) 虚拟继承
  如同下面的继承情况:#include  #include  using namespace std; class Point { public: Point() { printf("Point : constructor\n"); } virtual ~Point() { printf("Point : destructor\n"); } protected: float _x, _y; }; class Point3d : public virtual Point { public: Point3d() { printf("Point3d : constructor\n"); } ~Point3d() { printf("Point3d : destructor\n"); } protected: float _z; }; class Vertex : public virtual Point { public: Vertex() { printf("Vertex : constructor\n"); } ~Vertex() { printf("Vertex : destructor\n"); } protected: float _w; }; class Vertex3d : public Point3d, public Vertex { public: Vertex3d() { printf("Vertex3d : constructor\n"); } ~Vertex3d() { printf("Vertex3d : destructor\n"); } protected: float _u; }; int main () { Vertex3d *pV3d = new Vertex3d; delete pV3d; pV3d = NULL; return 0; } 在这种情况下,Vertex3d压制了它的两个父类对Point constructor的调用,这个调用工作由Vertext3d本身来完成。所以输出为:  
  
  b) vptr初始化语意学
  接着上面的例子:#include  #include  using namespace std; class Point { public: Point() { self(); } virtual ~Point() { printf("Point : destructor\n"); } virtual void self() { printf("Point : self\n"); } protected: float _x; }; class Point3d : public virtual Point { public: Point3d() { self(); } ~Point3d() { printf("Point3d : destructor\n"); } void self() { printf("Point3d : self\n"); } protected: //float _z; }; class Vertex : public virtual Point { public: Vertex() { self(); } ~Vertex() { printf("Vertex : destructor\n"); } void self() { printf("Vertex : self\n"); } protected: //float _w; }; class Vertex3d : public Point3d, public Vertex { public: Vertex3d() { self(); } ~Vertex3d() { printf("Vertex3d : destructor\n"); } void self() { printf("Vertex3d : self\n"); } protected: //float _u; }; int main () { Vertex3d *pV3d = new Vertex3d; delete pV3d; pV3d = NULL; return 0; } 输出为: 
  
  这说明,虽然new出来的是一个Vertex3d对象,但是在每个constructor中调用的self,既不是基类的self,也不是Vertex3d的self,而都会被决议为是当前class的self。这个和vptr的初始化有关,因为vptr的初始化,是在base class constructor调用操作之后,在当前constructor执行或者当前constructor的member initialization list初始化之前。
  一个constructor的执行算法如下:
  1. 执行所有virtual base class以及上一层base class的constructor。
  2. 初始化vptr。
  3. member initialization list执行。
  4. 执行constructor的代码。
  5.3 对象复制语意学
  如果我们明确的想要拒绝把一个class object指定给另一个class object,那么我们可以将copy assignment operator指定为private,并且不提供它的定义。
  一个class对于默认的copy assignment operator,在以下四种情况下不会出现bitwise copy语意:
  1. 当class内带一个class object,其class带有一个copy assignment operator;
  2. 当一个class的base class有一个copy assignment operator时;
  3. 当一个class声明了任何的virtual functions时;(因此不必担心vptr是否会被copy)
  4. 当class继承自一个virtual base class时;
  5.5 解构语意学
  一个destructor的执行算法与constructor类似,但顺序相反:
  1. destructor函数本身首先被执行;
  2. 如果class member带有destructor,那么它们会以声明顺序的相反顺序被调用;
  3. 如果一个object带有一个vptr,那么vptr被重新设定,指向适当的base class的virtual table;
  4. 如果有直接的nonvirtual base class拥有destructor,那么它们会以声明顺序的相反顺序执行;
  5. 如果有任何的virtual base class拥有destructor,而当前讨论的这个class是最尾端的class(保证virtua base class的destructor只被调用一次),那么它们会以其原来的构造顺序的相反顺序执行。
  附:#include  #include  using namespace std; class Point { public: Point() { } virtual ~Point() { } protected: float _x; }; class Point3d : public virtual Point { public: Point3d() { } ~Point3d() { } public: //int _z; }; class Vertex : public virtual Point { public: Vertex() { } ~Vertex() { } protected: //float _w; }; class Vertex3d : public Point3d, public Vertex { public: Vertex3d() { } ~Vertex3d() { } protected: //float _u; }; int main () { Vertex3d *pV3d = new Vertex3d; printf("%d\n", sizeof(Point)); printf("%d\n", sizeof(Point3d)); printf("%d\n", sizeof(Vertex)); printf("%d\n", sizeof(Vertex3d)); delete pV3d; pV3d = NULL; return 0; } 
  
  输出的结果可以分析为:
  class Point有一个4bytes的float member和一个4bytes的vptr,该vptr中含有virtual destructor的地址;
  class Point3d有一个4bytes的float member和两个4bytes的vptr,其中一个是继承下来的,另外一个含有virtua base class的offset;
  class Vertex同上;
  class Vertex3d有一个8bytes的Point,还分别有两个4bytes的Point3d和Vertex;
  但是,如果去掉Point中的member:#include  #include  using namespace std; class Point { public: Point() { } virtual ~Point() { } protected: //float _x; //去掉 }; class Point3d : public virtual Point { public: Point3d() { } ~Point3d() { } public: //int _z; }; class Vertex : public virtual Point { public: Vertex() { } ~Vertex() { } protected: //float _w; }; class Vertex3d : public Point3d, public Vertex { public: Vertex3d() { } ~Vertex3d() { } protected: //float _u; }; int main () { Vertex3d *pV3d = new Vertex3d; printf("%d\n", sizeof(Point)); printf("%d\n", sizeof(Point3d)); printf("%d\n", sizeof(Vertex)); printf("%d\n", sizeof(Vertex3d)); delete pV3d; pV3d = NULL; return 0; } 输出: 
  
  我的理解是:
  class Point有一个4bytes的vptr,该vptr中含有virtual destructor的地址;
  class Point3d有一个4bytes的float member,由于virtual base class没有member,所以就没有一个vtable来存放virtual base class的offset,而Point3d本身也没有virtual function;
  class Vertex同上;
  class Vertex3d包含了一个Point3d和一个Vertex;
  以上测试编译环境为GCC。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics