深度探索C++对象模型之第四章:函数语义学
C++有三种类型的成员函数:1.static/nonstatic/virtual
一、成员的各种调用方式
C with Classes 只支持非静态成员函数(Nonstatic Member Functions)。
20世纪80年代中期,又引入了virtual functions,但有一种常见的观点是virtual 函数只不过是一种跛脚的函数指针,没有什么用;
1987年,static member functions最后被引入。
1.1 非静态成员函数
设计准则之一就是非静态成员函数必须与一般非成员函数具有相同的效率,选择成员函数不应该带来任何额外负担,因为编译器已经将成员函数实例转换为对等的非成员函数实例。
例子如下:
这是magnitude3d的成员函数定义:
float Point3d::magnitude() const { return sqrt(_x * _x + _y * _y + _z*_z); }
这是magnitude3d非成员函数:
float magnitude3d(const Point3d * _this) { return sqrt(_this->_x * _this->_x + _this->_y * _this->_y + _this->_z * _this->_z); }
下面来看看编译器是如何将上述的成函数转换为非成员函数的:
- 改写函数的signature(原型)以安插一个额外的参数到成员函数中,用以提供一个存取管道,使类对象得以将此函数调用,该函数称为this指针。
//non-const nonstatic member的扩张过程 Point3d Point3d::magnitude(Point3d* const this) //member function是const的则如下所示: Point3d Point3d::mgnitude(const Point3d *const this);
- 将每个对非静态数据成员的存取操作,改为经由this指针来存取
{ return sqrt(this->_x * this->_x + this->_y * this->_y + this->_z * this->_z ); }
- 将memberfunction重新写成一个外部函数,将函数名经过“mangling”处理(名字修饰)处理,使得它在程序中称为独一无二的词语:
extern magnitude_7Point3dFv( register Point3d * const this);
经过上述操作,该函数已经被转换好了,那么每个对该函数的操作都需要进行转换,意思就是,你代码中所有调用到该函数的部分都会被替换为那个独一无二的词语。
再举个例子如下所示:
Point3d //这个Point3d是返回类型的值 Point3d::normalize() const { registe float mag = magnitude(); return Point3d( _x /mag , _y /mag, _z /mag); }
上述代码经过编译器会转换成下述格式:
void normalize_7Point3Fv(register const Point3d * const this, Point3d &_result) { register float mag = this->magnitude(); //_result用以取代返回值(return value) _result.Point3d::Point3d ( this->_x/mag, this->_y/mag, this->_z/mag ); return ; }
经过上述操作,可以节省default constructor初始化引起的额外负担。
1.2 名称的特殊处理
我们讲个比较好玩的东西,Name Mangling,名称的特殊处理,这是个什么东西呢?
一般而言,member的前面会加上类的名字,如下所示:
class Bar {public :int val;...}
上其中的ival经过 name mangling后,会变成下面这个样子:
ival_3Bar;
为什么编译器会这么做呢? 考虑下述派生操作:
class Foo : public Bar (public int ival; ...);
由于Foo对象内部结合了基类和派生类对象两者:则Foo的内部描述如下所示:
class Foo { public: int ival_3Bar; int ival_3Foo; };
上不管你要处理哪个ival,通过name mangling都可以独一无二的找到,当然由于member function可以被重载,所以name mangling可以有各种各样的手法,比如参数类型和参数列表;
但是name mangling后的名字一般是不可见的。
1.3 虚成员函数(virtual member functions)
若normalize()是一个虚成员函数,那么下述调用将会被抓换为
ptr->normalize();
变成:
(*ptr->vptr[1])(ptr);
其中:
1.vptr是由编译器产生的指针,指向virtual table。它被安插在每个"声明有一个或多virtual functions"的class object中,其实vptr也难躲被mangled,因为在一个复杂的class派生体系中,可能存在多vptr。
2. 1 是virtual table slot 的索引值,关联到normalize();
3. 第二个ptr表示this指针;
类似道理:
如果magnitude()也是一个virtual function,它在normalize()中将会被转换为下述形式:
//register float mag = magnitude(); register float mag = (*this->vptr[2])(this);
由于Point3d::magnitude()是在Point3d::normalize()中调用的,后者已经由虚拟机制处置妥当,所以显式的调用Point3d::magnitude()会比较有效率,并因此压抑由虚拟机制而产生的不必要重复调用。
register float mag = Point3d::magnitude();
深度探索C++对象模型之第四章:函数语义学的更多相关文章
- 深度探索C++对象模型之第三章:数据语义学
如下三个类: class X { }: class Y :public virtual X { }; class Z : public virtual X {}; class A :public Y, ...
- 《深度探索C++对象模型》读书笔记(一)
前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...
- 拾遗与填坑《深度探索C++对象模型》3.3节
<深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...
- 拾遗与填坑《深度探索C++对象模型》3.2节
<深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...
- c++学习书籍推荐《深度探索C++对象模型》下载
百度云及其他网盘下载地址:点我 百度云及其他网盘下载地址:点我 编辑推荐 如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么这本<深度探索C++对象模型>正适合你 作者简介 ...
- 读书笔记《深度探索c++对象模型》 概述
<深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...
- 柔性数组-读《深度探索C++对象模型》有感 (转载)
最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...
- 柔性数组-读《深度探索C++对象模型》有感
最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...
- [读书系列] 深度探索C++对象模型 初读
2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...
随机推荐
- 【目录】ASP.NET Core 基础教程
ASP.NET Core 基础教程 ASP.NET Core 基础教程 ASP.NET Core 简介 ASP.NET Core Windows 环境配置 ASP.NET Core macOS 环境配 ...
- 【记录】Nginx错误could not build the server_names_hash you should increase server_names_hash_bucket_size: 32
今天遇到这个错误,现记录下解决方案: 在nginx的配置文件的http段中增加如下配置: server_names_hash_bucket_size 64; 下面是nginx官方文档解释: 如果定义了 ...
- vue 数字输入组件
index.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...
- Delphi 常用API 函数列表
Delphi 常用API 函数 AdjustWindowRect 给定一种窗口样式,计算获得目标客户区矩形所需的窗口大小AnyPopup 判断屏幕上是否存在任何弹出式窗口ArrangeIconicWi ...
- 【IP】虚拟IP原理
使用场景: 当这台机器出现故障时,自动动态切换到另一台热备的机器 高可用性HA(High Availability) 指的是通过尽量缩短因日常维护操作(计划)和突发的系统崩溃(非计划)所导致的停机时间 ...
- sql update语句
如果要更新数据库表中的记录,我们就必须使用UPDATE语句. UPDATE语句的基本语法是: UPDATE <表名> SET 字段1=值1, 字段2=值2, ... WHERE ...; ...
- webstorm使用说明
1.移动光标到的代码块的结尾处(开始处 [ ) ctrl+] 2.移动光标到的代码块的结尾处并选择 ctrl+shift+] 3.ctrl + b: 跳到变量申明处 4.多光标输入: ...
- PHP base64_decode+gzinflate压缩和解密代码图文教程
今天碰到的这个问题,是我在更换一个WP主题是遇到.目前的情况如下,我想要把如下的超链接去掉,后台代码找到了在sidebar1.php文件中. 打开此文件发现是一长串的字符: 经过百度.google后, ...
- MVC 中对返回的 data 进行压缩
在webAPI 中返回数据,在数据量比较大的情况的下,返回的data 也可能比较大,有时候可能大于1兆,因此对数据进行压缩能极大的提高数据下载到客户端的时间,提高页面的加载速度. 思路: 在web a ...
- P1435 回文字串
P1435 回文字串 题目背景 IOI2000第一题 题目描述 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成回文词.此题的任务是,求出将给定字符串变成回文词所需要插入的最 ...