深度探索C++对象模型 【第四章2】

来源:互联网 发布:招商网站留言数据提取 编辑:程序博客网 时间:2024/06/05 02:12

1:关于取地址的艺术~

  • 直接取一个非静态成员变量的地址时,得到的是其在class中的真实offset再加1。当绑定到真实的对象上再取其地址时,得到的是其在内存中的真正地址。
  • 取一个非静态成员函数的地址时,得到的是其在内存中真正的地址,但是要存取该函数,也需要对象的地址来配合。
  • 直接存取一个静态成员变量的地址时,无论通过对象还是class,得到的都是其在内存中的真正地址。
  • 直接存取一个静态成员函数的地址时,无论通过对象还是class,得到的都是其在内存中的真正地址。
2:使用一个指向成员函数的指针,如果是虚函数、多重继承、虚拟继承的情况,其成本会更高一点。
double (Point::*pmf)() = &Point::z;//pmf,一个指向成员函数的指针,被设置初值为Point::z(),调用方式:(point.*pmf)();或者(P->*pmf)();

3:指向虚函数的指针,虚函数机制仍然能够在使用指向“成员函数指针”的情况下运转!因为对一个虚函数取地址,由于其地址在编译期是未知的,所能知道的只是虚函数在vbtl中的索引值。也就是说,对虚成员函数取地址,所能获得的是其索引值。

4:由上述2/3可知,一个指向成员函数的指针需要既可以指向非虚函数也可以指向虚函数,但是指向虚函数是,得到的只是其索引值,而非虚函数得到的是其真实的地址。所以编译器必须定义pmf使他能够
  • 持有两种数值
  • 使得该数值能够区分索引值和真实的地址
5:cfront的做法是先进行一个判断,将指针转化为int,进行一定的判断,这种做法最多只能支持有128个虚函数,虽然有一定的限制,但却可行。

6:多重继承下指向成员函数的指针
  • 有的编译器设计了一种结构体,里面的数据分别保存vbtl中的索引(初始值为-1)和非虚函数的地址
  • 不同编译器有自己不同的风格
7:函数指针的效率而言,多重继承和虚拟继承一样即使在编译器优化的条件下还会有一定的额外时间负担

8:inline函数
  • 将class中的成员存取函数声明为inline,我们可以保持直接存取member的高效率,亦保持了函数的封装性。
  • 关键词inline只是一种请求,如果这项请求被接受,编译器会用一个表达式来合理地将这个函数展开。
  • 将函数展开之后所带来的执行成本会比一般的函数调用以及返回机制多带来的成本要低。
  • 一般编译器会计算函数中“赋值”、“函数调用次数”、“虚函数调用次数”等等,每种类型会有一个相应的权值,而inline函数的复杂度就会以这些权值的总和来决定
9:编译器的inline分析
  • 分析函数的定义,决定是否能转化为inline,如果不行,他会被转化为一个static函数,并在被编译模块内产生对应的函数定义。
  • 真正的inline函数扩展操作是在调用时才会发生。
  • 有很多的编译器(UNIX)认为不值得在inline上大费周章,所以想要看其是否真正实现了inline,你得去汇编器里看看
10:在inline函数的扩展期间
  • 每一个形式参数都会被转化为实际参数,如果有常量表达式的出现,会在替换之前完成对其的求值操作,后继的inline替换,可以直接绑定。
11:在inline函数中,每一个局部变量都必须被放在函数调用的一个封闭区段中,拥有一个独一无二的名称。这样可能会导师大量的临时性对象的产生。

12:inline函数对于封装提供了一种必要的支持,可以有效存储Nonpublic中的数据。但如果其调用次数太多,可能会产生大量的扩展码,使得程序大小暴涨。inline中再有inline可能会使得连锁复杂度太高无法扩展。



原创粉丝点击