第四章 function语意学(二)

     取一个nontatic data member的地址,得到是member在class布局中的offset;取一个nostatic member function的地址,如果是nonvirtual,则得到他在内存中真正的地址,所有的nonstatic member function都需要对象的地址(this)

     指向member function 的指针

double (Point::* pmf)();
     定义并初始化:

double(Point::*coord)()=&Point::x;
     调用:

(origin.*coord)();
//或者
(ptr->*coord)();
      指向member function 的指针的声明语法,以及指向“member selection运算符“的指针,其作用是作为this指针的空间保留着。而static member function没有this指针,因此其类型是函数指针,而不是member function的指针。

      对于除了virtual function,多重继承以及virtual base classes的情况,指向member function的指针和指向nonmember function的指针成本相当。


指向virtual member function的指针

      虚拟机制支持指向member function的指针,但virtual function的地址在编译期未知,而只能取到其在virtual table中的索引值

class Point
{
public:
    virtual ~Point();
    float x();
    float y();
    virtual float z();
}

//声明函数指针
float (Point::*pmf)()=&Point::z;
Point *ptr=new Point;

//则对z()的调用
(ptr->*pmf)();
//会转化为
(*ptr->vptr[(int)pmf])(ptr);

       指向函数的指针能够寻址出nonvirtual 和virtual  member function,前者代表内存地址,后者代表在virtual table中的索引值。pmf必须能够对上述两种值加以区分。

       作者提到一种解决方法,但该种方法必须假设继承体系中最多只有128个virtual functions

(((int)pmf)&127)
?                            //nonvirtual invocation
(*pmf)(ptr)
:                             //virtual invocation
(*ptr->vptr[(int)pmf](ptr));

在多重继承之下,指向Member Funcions的指针

       

struct _mptr{
    int delta;
    int index;
    Union{
         ptrtofunc   faddr;//nonvirtual member function地址
         int         v_offset;//virtual table索引
    };
};
上述结构用于支持多重继承下指向member function的指针。再该模型下

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

         1、判断成本

         2、当传递一个不变值的指针给member function时,需要产生一个临时对象

extern Point3d foo(const Point3d&, Point3d(Point3d::*)());
void bar(const Point3d& p){
     Point3d pt = foo(p,&Point3d::normal);
}

//如果&Point3d::normal为
{0,-1,10727417}
//则会产生一个临时性的对象,有明确的初值
//虚拟C++码
_mptr temp={0,-1,10727417};//delta=0,index=-1,faddr=10727417
foo(p,temp);

4-5 Inline Functions内联函数

       关键词inline知识一项请求,如果这项请求被接受(在某个层次上,其执行成本比一般的函数调用及返回机制所带来的负荷低),编译器就必须认为他可以用一个表达式合理地将这个函数扩展开来。

      处理过程:

      1.分析函数定义,以决定函数的“intrinsic inline ability”。如果函数太复杂,被判断为不可称为inline,会被转为一个static函数。

      2.在调用处将该inline函数扩展。

注:1 : inline的declaration和definition一定要在同一个档案里面

       2 : class的话,member function可以implicit inline,有无template都一样

       3 : 一般function,要inline一定得在function的declaration前面加上"inline"的关键字,一般function不会implicit inline。

       4 : implicity inline的话,你可以在class内的declaration宣告inline或在class外的definition宣告,也可以同时宣告

       5:,如果一个inline函数会在多个源文件中被用到,那么必须把它定义在头文件中

形式参数

       #define和inline的区别在于#define使用预编译器,没有使用堆栈,所以只是预编译器符号表上的简单替换,不能进行参数有效性检测以及使用C++类的成员访问控制。

       inline代码放入预编译符号表中,高效;但它是个真正的函数,调用时有严格的参数检测,可以作为类的成员函数

       替换时间:宏函数是在预编译阶段执行代码替换,inline函数是在编译的过程中执行代码替换

       替换性质,宏定义的替换仅仅是文本替换,inline函数是真正意义上的代码替换

注:在调用时,如果参数是一个表达式,宏定义进行简单的表达式替换;内敛函数先求表达式的值,再传递给函数。

      由于在inline的每个调用处会直接展开,对于实参的多次求值操作可能会多次引入临时性对象。为避免这种情况,在替换之前完成求值操作。

     

inline int bar()
{
    int minval;
    int val1=1024;
    int val2=2048;
    /*(1)*/ minval = min(val1,val2);
    /*(2)*/ minval = min(1024,2048);
    /*(3)*/ minval = min(foo(),bar()+1);
    return minval;
}

扩展情况如下

//(1)参数直接代换
minval = val1 < val2 ? val1 : val2;

//(2)代换之后直接使用常量
minval=1024;

//(3)有副作用,所以导入临时对象,这样可以避免每次都重新计算
int t1;
int t2;
minval = (t1=foo()),(t2=bar()+1),t1<t2?t1:t2;

局部变量

        inline函数中的每一个局部变量都必须被放在函数调用的一个封闭区段中,拥有独一无二的名称,如果inline函数以单一的表达式扩展多次,那么每次扩展都需要自己的一组局部变量。如果inline函数以分离的多个式子被扩展多次,则只需要一组局部变量,就可以重复使用(因为他们被放在一个封闭区段中,有自己的scope)。

//单一表达式
minval = min (val1, val2)+min (foo(),foo()+1);

//分离的多个式子
minval1=min(val1, val2);
minval2=min(foo(),foo()+1);
minval=minval1+minval2;

           inline可能导致大量剧对象的产生。

         一个inline如果被调用太多次,会产生大量的扩展码,使程序的大小暴涨。

         inline中再有inline,可能会使得一个表面上看起来平凡的inline因其连锁复杂度而没办法扩展开(复杂class体系下的constructor...)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值