快速业务通道

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

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-30
o;之指针将会带来新的问题,请注意下面的程序片段:

float (Point::*pmf)() = &Point::z;
Point *ptr = new Point3d;

其中,pmf是一个指向member function的指针,被设值为Point::z()(一 个virtual function)的地址,ptr则被指向一个Point3d对象。

如果我们直接经由ptr调用z() :

ptr->z();  // 调用的是Point3d::z()

但如果我们经由pmf间接调 用z():

(ptr->*pmf)();  // 仍然调用的是Point3d::z()

也就是说 ,虚拟机制仍然能够在使用“指向member function之指针”的情况下运行,但问题是如何实 现呢?

对一个nonstatic member function取其地址,将获得该函数在内存中的地址;而对一个 virtual member function取其地址,所能获得的只是virtual function在其相关之virtual table中的 索引值。因此通过pmf来调用z(),会被内部转化为以下形式:

(*ptr->vptr[(int) pmf])(ptr);

但是我们如何来判断传给pmf的函数指针指向的是内存地址还是virtual table中的索引值呢?例如以下两个函数都可指定给pmf:

// 二者都可以指定给pmf
float Point::x() { return _x; }  // nonvirtual函数,代表内存地址
float Point::z() { return 0; }  // virtual函数,代表virtual table中的索引值

cfront 2.0是通过判断 该值的大小进行判断的(这种实现技巧必须假设继承体系中最多只有128个virtual functions)。

为了让指向member functions的指针也能够支持多重继承和虚拟继承,Stroustrup设计了下面一 个结构体:

// 用以支持在多重继承之下指向member functions的指针
struct _mptr {
int delta;
int index;
union {
ptrtofunc faddr;
int v_offset;
};
};

其中,index表示virtual table索引,faddr表示 nonvirtual member function地址(当index不指向virtual table时,被设为-1)。

在该模型之 下,以下调用操作会被转化为:

(ptr->*pmf)();
// 内部转化为
(pmf.index < 0)
? (*pmf.faddr)(ptr)  // nonvirtual invocation
: (*ptr- >vptr[pmf.index](ptr)  // virtual invocation

对于如下的函数调用:

(pA.*pmf)(pB);  // pA、pB均是Point3d对象

会被转化成:

pmf.iindex < 0
? (*pmf.faddr)(&pA + pmf.delta, pB)
: (*pA._vptr_Point3d[pmf.index].faddr)(&pA + pA._vptr_Point3d[pmf.index] + delta, pB);

***Inline Functions***

在inline扩展期间,每一个形式参数都会被对应 的实际参数取代。但是需要注意的是,这种取代并不是简单的一一取代(因为这将导致对于实际参数的 多次求值操作),而通常都需要引入临时性对象。换句话说,如果实际参数是一个常量表达式,我们可 以在替换之前先完成其求值操作;后继的inline替换,就可以把常量直接绑上去。

举个例子,假 设我们有以下简单的inline函数:

inline int min(int i, int j)
{
return i < j ? i : j;
}

对于以下三个inline函数调用:

minval = min(val1,val2);
minval = min(1024,2048);
minval = min(foo(),bar() +1);

会分别被扩展为:

minval = val1 < val2 ? val1 : val2;  // 参数直接代换
minval = 1024;  // 代换之后,直接使用常量
int t1;
int t2;
minval = (t1 = foo()), (t2 = bar()+1),t1 < t2 ? t1 : t2;  //有副作用,所以导入临时对 象

inline函数中的局部变量,也会导致大量临时性对象的产生。

inline int min(int i, int j)
{
int minval = i < j ? i : j;
return minval;
}

则以下表达式:

minval = min(val1, val2);

将被转化 为:

int _min_lv_minval;
minval = (_min_lv_minval = val1 < val2 ? val1 : val2),_min_lv_minval;

总而言之,inline函数中的局部变量,再加上有

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号