【C++】深度探索C++对象模型读书笔记--Function语意学(The Semantics of Function)

Member的各种调用方式:

  Nonstatic member function(非静态成员函数)的调用方式

  编译器会将”member 函数实例“转换为对等的”nonmember函数实例“。

  对于非静态成员函数

float Point3d::magnitude3d() const{...}

  转换步骤如下:

  1. 改写函数的signature(意指:函数原型)以安插一个额外的参数到member function中,用以提供一个存取管道,使class object得以将此函数调用。该额外参数被称为this指针:

//non-const nonstatic member的扩张过程
Point3d Point3d::magnitude(Point3d *const this)

如果是member function 是const,则变成:
//const nonstatic member的扩张过程:
 Point3d Point3d::magnitued(const Point3d *const this)

  2. 将每一个”对nonstatic data member的存取操作”改为经由this指针来存取:

  3.将member function重新写成一个外部函数。将函数名称经过“mangling”处理,使它在程序中成为独一无二的词汇:

extern magnitude_7Point3dFv(
    register Point3d *const this);

  现在这个函数已经被转换好了,而其每一个调用操作也都必须被转换。于是:

1 obj.magnitude();
2 变成了:
3     magnitude_7Point3dFv(&obj);
4 5     ptr->magnitued();
6 变成了:
7     magnitude_7Point3dFv(ptr);

 

  Virtual Member Functions(虚拟成员函数)

  使用指针调用虚拟函数:

  如果normalize()是一个virtual member function,那么以下的调用:

ptr->normalize();

  将会被内部转化为:

(*ptr->vptr[1])(ptr);

  其中:

  •   vptr表示由编译器产生的指针,指向virtual table。它被安插在每一个“声明有(或继承自)一个或多个virtual functions”的class object中
  •   1是virtual table slot 的索引值,关联到normalize()函数。
  •   第二个ptr表示this指针。

  

  使用类对象调用虚拟函数:

  使用类对象调用虚拟函数,其解析方式和非静态成员函数一样。对于上一节中的normalize()函数。调用方式最终被解析为:

normalize_7Point3dFv(&obj);

 

   Static member Function(静态成员函数)

  1.静态成员函数的主要特性:

  •   它不能直接存取class中的nonstatic members
  • 它不能被声明为cosnt、volatile或virtual
  • 它不需要经由class object才被调用--虽然大部分时候它是这样被调用的

 

  2. 取一个静态成员函数的地址,获得的将是其在内存中的位置,也就是其地址。由于static member function没有this指针,所以其地址类型并不是一个“指向class member function的指针”,而是一个“nonmember函数指针“

 

Virtual Member Functions(虚拟成员函数)

  1. 识别一个class是否支持多态,唯一适当的方法就是看看它是否有任何虚函数,只要类拥有虚函数。只要一个类拥有一个虚函数,那么就可以说该类支持多态。

  2. 一个类只会含有一个virtual table。每个table内含其对应之class object中所有的active virtual functions函数实例的地址。这些active virtual functions包括:

    1.这一class所定义的函数实例。它会改写一个可能存在的base class virtual function函数实例

    2. 继承自base class的函数实例。这是在derived class决定不改写virtual funciton时才会出现的情况。

    3. 一个pure_virtual_called()函数实例,它既可以扮演pure virtual function的空间保卫者角色,也可以当作执行期一场处理。

 

  我们定义如下继承体系:

class Point {
public:
    virtual ~Point();
    virtual Point& mult(float) = 0; //纯虚函数,调用此函数程序会结束
    
    float x() const {return _x}; //不会被放在virtual table中,因为不是虚函数
    virtual float y() const {return 0;}
    virtual float z() const {return 0;}

protected:
    Point(float x = 0.0);
    float _x;
};

class Point2d: public Point {
public:
    Point2d(float x = 0.0, float  y = 0.0)
        :Point(x), _y(y){}
    ~Point2d();

    //改写base class virtual functions
    Point2d& mult(float);
    float y() const {return _y;}

protected:
    float _y;
};

class Point3d: public Point2d {
public:
    Point3d(float x = 0.0, float y = 0.0, float z = 0.0)
        :Point2d(x, y), _z(z){}

    ~Point3d();

    //改写base class virtual functions
    Point3d& mult(float);
    float z() const { return _z;}

protected:
    float _z;
};


则它们的virtual table的布局是这样的:

  

 

  多重继承:

    我们有如下类继承体系:

    

class Base1 {
public:
    Base1();
    virtual ~Base1();
    virtual void speakClearly();
    virtual Base1 *clone() const;
protected:
    float data _Base1;
};

class Base2 {
public:
    Base2();
    virtual ~Base2();
    virtual void mumble();
    virtual Base2 *clone() const;
protected:
    float data_Base2();
};

class Derived : public Base1, public Base2 {
public:
    Derived();
    virtual ~Derived();
    virtual Derived *clone() const;
protected:
    float data _Derived;
};

  在多重继承之下,一个derived class内含n-1个额外的virtual tables, n表示其上一层base classes的个数(因此,单一继承将不会有额外的virtual tables)。对于本例的Derived而言,会有两个virtual tables被编译器产生出来:

  1. 一个主要实例,与Base1(最左端base class有关)

  2. 一个次要实例,与Base2(第二个base class有关)

  针对每一个virtual tables,Derived对象中有对应的vptr。vptrs将在构造函数中被设立初值。(经由编译器所产生出来的代码)。

  用以支持“一个class拥有多个virtual tables”的传统方法是,将每个tables以外部对象的形式产生出来,并给予独一无二的名称。例如,Derived所关联的两个tables可能这样的名称:

  vtbl_Derived; //主要表格

  vtbl_Base2_Derived; //次要表格

  于是当你将一个Derived对象地址指定给一个Base1指针或Derived指针时,被处理的virtual table是主要表格vtbl_Derived.而当你将一个Derived对象地址指定一个Base2指针时,被处理的virtual table是次要表格vtbl_Base2_Derived.

  Virtual Table布局如下:

  

  注意:两个virtual table中都有Derived类的虚函数地址。

posted @ 2015-07-18 15:10  vincently  阅读(268)  评论(0编辑  收藏  举报