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++对象模型之第四章:函数语义学的更多相关文章

  1. 深度探索C++对象模型之第三章:数据语义学

    如下三个类: class X { }: class Y :public virtual X { }; class Z : public virtual X {}; class A :public Y, ...

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

    前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...

  3. 拾遗与填坑《深度探索C++对象模型》3.3节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  4. 拾遗与填坑《深度探索C++对象模型》3.2节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  5. c++学习书籍推荐《深度探索C++对象模型》下载

    百度云及其他网盘下载地址:点我 百度云及其他网盘下载地址:点我 编辑推荐 如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么这本<深度探索C++对象模型>正适合你 作者简介 ...

  6. 读书笔记《深度探索c++对象模型》 概述

    <深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...

  7. 柔性数组-读《深度探索C++对象模型》有感 (转载)

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  8. 柔性数组-读《深度探索C++对象模型》有感

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  9. [读书系列] 深度探索C++对象模型 初读

    2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...

随机推荐

  1. Linux下载工具-Wget

    一.安装 进入系统后执行: # yum install wget 二.常用命令使用 以下亲测可用:[文件保存在当前命令执行的文件夹中] 1.wget下载单个文件 # wget url(文件地址,如ht ...

  2. ItunesConnect:苹果内购项目元数据缺失

    问题描述: 添加内购的App审核时被拒,原因为:ios内购 元数据丢失 问题原因: 审核信息里的 “审核屏幕快照” 和 “备注” 要填写,不然就失败的. 示例图: 1.屏幕快照和审核备注都需要填写   ...

  3. Andrdoid中对应用程序的行为拦截实现方式之----从底层C进行拦截

    之前的一篇概要文章中主要说了我这次研究的一些具体情况,这里就不在多说了,但是这里还需要指出的是,感谢一下三位大神愿意分享的知识(在我看来,懂得分享和细致的人才算是大神,不一定是技术牛奥~~) 第一篇: ...

  4. delphi 时间

    DELPHI高精度计时方法 //取毫秒级时间精度(方法一): var t1,t2:int64; r1:int64; begin t1:=GetTickCount;//获取开始计数 WINDOWS AP ...

  5. nuxt.js 本地开发跨域问题(Access-Control-Allow-Origin)及其解决方案

    先运行npm i @gauseen/nuxt-proxy -D 再nuxt.config.js的module.exports 里面添加如下代码 modules:[ '@nuxtjs/axios', / ...

  6. tomcat8.5在centos部署阿里云免费证书

    最近在做微信小程序,部署完服务器之后,发现报了个错误,说是我的域名不在以下合法域名列表中.对比了一下才发现我的域名还是http的没升级到https,之后我就到阿里云去申请了证书.中间有一次审核失败,查 ...

  7. Codeforces gym102222 B.Rolling The Polygon 凸包/余弦定理

    题意: 有一个不保证凸的多边形,让你滚一圈,计算某点滚出的轨迹多长. 题解: 求出凸包后,以每个点为转轴,转轴到定点的距离为半径,用余弦定理计算圆心角,计算弧长. #include<iostre ...

  8. Wannafly Winter Camp Day8(Div1,onsite) E题 Souls-like Game 线段树 矩阵乘法

    目录 Catalog Solution: (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 Catalog @ Problem:传送门  Portal  原题目描述在最下面.  简单的 ...

  9. SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")时间转换问题

    SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")时间转换问题 程序代码: import java.text.ParseException; i ...

  10. 戏说 .NET GDI+系列学习教程(三、Graphics类的方法的总结)