深度探索C++对象模型--Function语意学

成员函数调用方式

Nonstatic Member Function(非静态成员函数)

-Nonstatic Member Function设计准则:与一般非成员函数(nonmember function)有相同的执行效率。因此,实际上编译器内部将Nonstatic Member 函数实体转化为对等的nonmember 函数实体。
-转换过程:
1. 添加额外this指针,提供数据存取管道
2. 修改函数体内成员数据存取方式,改为使用this指针存取
3. 对函数名字重新“mangling”修饰处理

class A{
public:
    int x, y;
    int func();
}
int A::func(){ return x+y; }      //Nonstatic Member function
int A::func(A *const this)        //1.添加额外参数this指针
int A::func(A *const this){
    return this->x + this->y;}    //2.改为由this指针存取成员数据
extern int func_1AFv(A *const this) //3.对函数名进行“mangling”修饰

obj.func() ---> func_1AFv(&obj)

名称特殊处理(name mangling):

member function重载化,以提供独一无二名称,采用该手法。

+++

//可能的修饰方法:
int Point::foo(float x)   ---> int foo_5PointFf(float x)
int Point::foo(void)   ---> int foo_5PointFv()

Static Member Function(静态成员函数)

-静态成员函数没有this指针:
 1. 不用直接存取class中nonstatic members
 2. 不能被声明为const, volatile 或者virtual
 3. 不需要有class object才能被调用

-Static Member Function会被编译器转化为nonmember形式,实际上该类函数产不多等同于nonmember function。
static int A::func()   //静态成员函数
//各种方式调用静态函数,均转换成通过类作用于直接调用
ptr->func()/obj.func()/A::func() --> A::func()
//函数mangling修饰
A::func() ---> func_1ASFv()  //SFv表示静态成员函数,参数void

Virtual Member Function(虚成员函数)

//1是virtual table slot索引,关联到func函数
ptr->func() -->(*ptr->vptr[1])(ptr)
//明确的调用可以抑制虚拟机制
A::func()
// 通过该obj调用不支持多态
obj.func() ---> func_1AFv(&obj)

-通过class object调用virtual function的操作会被编译器转换为一般的nonmember member function,不呈现多态。

下面将虚函数的调用。

Virtual Member Functions

c++多态:以一个public base class的指针,寻址出一个derived class object。

//调用虚函数,如何在执行期确定func()实体
ptr->func()
  • 编译期间完成的事情:
    -给每一个class object安插由编译器内部产生的vptr
    -给vtbl每一个virtual function一个固定的slot,在整个继承体系中保持与特定virtual funciton相联

  • vtbl包含的virtual function有:
    -该class所定义的函数实体,包括覆盖base class中的virtual function
    -继承自base class的实体,并决定不覆盖
    -pure_virtual_called()纯虚函数

单一继承

class Point {
public:
    virtual ~Point();   //slot 1
    virtual Point& mult (float) = 0   //slot 2
    float x() const {return _x;}
    virtual float y() const {return 0;}   //slot 3
    virtual float z() const {return 0;}   //slot 4
protected:
    Point (float x = 0.0);
    float _x;   
}

class Point2d:public Point {
public:
    ~Point2d();   //slot 1
    Point2d& mult (float)   //函数覆盖 slot 2
    float y() const {return _y;}   //函数覆盖 slot 3
protected:
    float _y;   
}

class Point3d:public Point2d {
public:
    ~Point3d();   //slot 1
    Point3d& mult (float)   //函数覆盖 slot 2
    float z() const {return _z;}   //函数覆盖 slot 4
protected:
    float _z;   
}


//一般来说我们事先并不知道ptr所指对象真正类型
//所以不知道哪个mult实体会被调用,但mult()固定在slot 2中是确定的
ptr->mult()
//因此编译器如下转换
//执行期唯一需要做的就是确定哪一个slot 2的实体
(*ptr->vptr[2])(ptr)

这里写图片描述

多重继承

//编译时期就将指针转移至第二个base class起始地址
Base2 *pbase2 = new Derived;
//执行时需要调整pbase2至Derived起始地址
delete pbase2;   //该行代码无法在编译时知道pbase2的真实对象,执行时才知道

-多重继承结构如下:Derived会有两个vtbl被编译器产生:(1)主体实体,与base1(最左端base class)共用 (2)次要实体,与base2有关
这里写图片描述

-三种需要调整指针的情况
1 通过指向base2的指针,调用derived class virtual function。

//编译时期就将指针转移至第二个base class起始地址
Base2 *pbase2 = new Derived;
//执行时需要调整pbase2至Derived起始地址
delete pbase2;

2 通过指向derived class的指针,调用第二个base claass中的一个继承而来的virtual function。

//编译时期就将指针转移至第二个base class起始地址
Derived *pder = new Derived;
//执行时需要调整pder以指向Base2 subobject
pder->mumble;   //调用Base2::mumble()

3 三个clone函数实体返回值类型不同

//编译时期就将指针转移至第二个base class起始地址
Base2  *pbase2 = new Derived;
//调用Derived* Derived::clone()
//需要将pbase2指针调整至Derived class起始处
//返回值时又需要重新调整至Base2 subobject
Base1 *pbase2_new = pbase2->clone;

虚拟继承

详见链接:
http://blog.csdn.net/isunn/article/details/45535951

指向Member Function指针

指向nonvirtual function指针

-得到真实地址,但它需要绑定与某个class object上,才能通过它调用。

double (Point::*coord) = &Point::x;  //nonvirtual function
//调用函数
(obj.*coord) ()
//被编译器转化
(coord)(&obj)  //&obj为this指针

-static member function函数地址为普通函数指针,因为没有this指针。

指向virtual function指针

virtual function地址在编译时期是未知的,但是与之相关的vtbl slot的索引值是固定的。所以取virtual function地址只能获得其索引值。

class Point{
public:
    virtual ~Point();   //slot 1
    virtual float z();  //slot 2
}
float (Point::*pmf) = Point::z;   //= 2
Point *ptr = new Point2d;
ptr->*pmf;
//被编译器转化为
(*ptr->vptr[(int)pmf](ptr));

多重继承下 member function指针

问题:如何区别Member Function指针指向地址还是virtual table索引?
方法:修改Member Function指针mptr结构体,mptr->index正负判别。

struct __mptr {
    int delta;
    int index;  //virtual function时:vtbl索引 nonvirtual时为-1
    union{
        ptrtofunc faddr;   //nonvirtual 时函数地址
        int       v_offse;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值