转载自:http://c.biancheng.NET/cpp/biancheng/view/2996.html点击打开链接

从上节的例子可以看出,对象的内存模型中只保留了成员变量,除此之外没有任何其他信息,程序运行时不知道 obj 的类型为 Demo,也不知道它还有一个成员函数 display()。那么,究竟是如何通过对象调用成员函数的呢?

C++函数的编译

C++和C语言的编译方式不同。C语言中的函数在编译时名字不变,或者只是简单的加一个下划线_(不同的编译器有不同的实现),例如,func() 编译后为 func() 或 _func()。

而C++中的函数在编译时会根据命名空间、类、参数签名等信息进行重新命名,形成新的函数名。这个重命名的过程是通过一个特殊的算法来实现的,称为名字编码(Name Mangling)。

Name Mangling 是一种可逆的算法,既可以通过现有函数名计算出新函数名,也可以通过新函数名逆向推演出原有函数名。

Name Mangling 可以确保新函数名的唯一性,只要命名空间、所属的类、参数签名等有一个不同,那么产生的新函数名也不同。

如果你希望看到经算法产生的新函数名,可以只声明而不定义函数,这样调用函数时就会产生链接错误,从报错信息中就可以看到。请看下面的代码:

  1. #include<iostream>
  2. using namespace std;
  3. void display();
  4. void display(int);
  5. namespace ns{
  6. void display();
  7. }
  8. class Demo{
  9. public:
  10. void display();
  11. };
  12. int main(){
  13. display();
  14. display(1);
  15. ns::display();
  16. Demo obj;
  17. obj.display();
  18. return 0;
  19. }

该例中声明了四个同名函数,包括两个具有重载关系的全局函数,一个位于命名空间 ns 下的函数,以及一个属于类 Demo 的函数。它们都是只声明而未定义的函数。

编译源代码即可看到错误信息:

小括号中就是 Name Mangling 产生的新函数名,它们都以”?“开始,以区别C语言中的”_“。

上图是VS2010产生的错误信息,不同的编译器有不同的 Name Mangling 算法,产生的函数名也不一样。

__thiscall、cdecl 是函数调用方式,有兴趣的读者可以猛击《函数的几种调用方式》一文深入了解。

除了函数,某些变量也会经 Name Mangling 算法产生新名字,不再赘述。

成员函数的调用

从上图可以看出,成员函数最终被编译成与对象无关的普通函数,如果函数体中没有成员变量,那问题就很简单,不用对函数做任何处理,直接调用即可。

如果成员函数中使用到了成员变量,该怎么办呢?成员变量的作用域不是全局,不经任何处理就无法在函数内部访问。

C++规定,编译成员函数时要额外添加一个参数,把当前对象的指针传递进去,通过指针来访问成员变量。

假设 Demo 类有两个 int 型的成员变量,分别是 a 和 b,并且在成员函数 display() 中使用到了,如下所示:

  1. void Demo::display(){
  2. cout<<a<<endl;
  3. cout<<b<<endl;
  4. }

那么编译后的形式类似于:

  1. void new_function_name(const Demo *p){
  2. //通过指针p来访问a、b
  3. cout<<p->a<<endl;
  4. cout<<p->b<<endl;
  5. }

调用时的形式类似于:

  1. new_function_name(&obj);

这样就完成了对象和成员函数的关联,只不过与我们从表明上看到的相反,不是通过对象找函数,而是通过函数找对象。

这一切都是隐式完成的,对程序员来说完全透明,就好像这个额外的参数不存在一样。

C++学习笔记(2)---2.5 C++函数编译原理和成员函数的实现的更多相关文章

  1. 读书笔记 effective c++ Item 23 宁可使用非成员非友元函数函数也不使用成员函数

    1. 非成员非友元好还是成员函数好? 想象一个表示web浏览器的类.这样一个类提供了清除下载缓存,清除URL访问历史,从系统中移除所有cookies等接口: class WebBrowser { pu ...

  2. 类1(this指针/const成员函数/类作用域/外部成员函数/返回this对象的函数)

    假设我们要设计一个包含以下操作的 Sales_data 类: 1.一个 isbn 成员函数,用于返回对象的 book_no 成员变量 2.一个 combine 成员函数,用于将一个 Sales_dat ...

  3. C++回调函数、静态函数、成员函数踩过的坑。

    C++回调函数.静态函数.成员函数踩过的坑. 明确一点即回调函数需要是静态函数.原因: 普通的C++成员函数都隐含了一个this指针作为参数,这样使得回调函数的参数和成员函数参数个数不匹配. 若不想使 ...

  4. C++ 学习笔记 (六) 继承- 子类与父类有同名函数,变量

    学习了类的继承,今天说一下当父类与子类中有同名函数和变量时那么程序将怎么执行.首先明确当基类和子类有同名函数或者变量时,子类依然从父类继承. 举例说明: 例程说明: 父类和子类有同名的成员 data: ...

  5. python学习笔记-(七)python基础--集合、文件操作&函数

    本节内容 1.集合操作 2.文件操作 3.字符编码与转码 4.函数操作 1.集合操作 集合是一个无序的.不重复的数据组合: 1.1 常用操作 它的作用是: 1)自动去重:列表变成集合,自动去重: &g ...

  6. C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类

    类继承 在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生. 从一个基类派生的继承称为单继承:从多个基类派生的继承称为多继承. //单继承的定义 class B:public A { ...

  7. MySQL学习笔记:upper、lower、ucase、lacase——字符串函数

    在MySQL中,通过利用upper.lower.ucase.lacase几个函数对字符串进行大小写转换. upper(str)——根据当前字符集映射返回字符串str,并将所有字符更改为大写.默认值是l ...

  8. Android(java)学习笔记216:多线程断点下载的原理(Android实现)

    之前在Android(java)学习笔记215中,我们从JavaSE的角度去实现了多线程断点下载,下面从Android角度实现这个断点下载: 1.新建一个Android工程: (1)其中我们先实现布局 ...

  9. Android(java)学习笔记159:多线程断点下载的原理(Android实现)

    之前在Android(java)学习笔记215中,我们从JavaSE的角度去实现了多线程断点下载,下面从Android角度实现这个断点下载: 1. 新建一个Android工程: (1)其中我们先实现布 ...

随机推荐

  1. 05-4-style的代替操作

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. elasticsearch query 和 filter 的区别

    Query查询器 与 Filter 过滤器 尽管我们之前已经涉及了查询DSL,然而实际上存在两种DSL:查询DSL(query DSL)和过滤DSL(filter DSL).过滤器(filter)通常 ...

  3. base64,AES,RSA,SHA和MD5等加密方式(jdk)

    import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.crypto.Cipher; import jav ...

  4. bzoj4788: [CERC2016]Bipartite Blanket

    2019.1.9交流题,现在看还是不会,,, 如果只有一边,那么Hall定理即可. 两边?分别满足Hall定理,就是合法的! 证明(构造方案): 左集合先任意形成一个合法匹配,单点增量加入右集合和与右 ...

  5. light oj 1219 树上贪心

    #include <iostream> #include <cstdlib> #include <cstring> #include <queue> # ...

  6. mysql知识点回顾与梳理

    一.sql语句执行顺序 from join on where group by avg,sum,count等各种函数 having select distinct order by(asc(升序),d ...

  7. jmeter-监听器介绍与使用

    12.jmeter-监听器介绍与使用 jmeter-监听器介绍与使用 察看结果树 Summary Report 聚合报告 Backend Listener Aggregate Graph 断言结果 C ...

  8. nslookup获取域名对应的的ip地址

    1.先用nslookup获得域名对应的主机ip:nslookup 域名 2.再根据主机ip获得对应的主机名称: host ip $ nslookup baidu.com Server: 127.0.1 ...

  9. 使用原生ajax及其简单封装

    原生ajax配置详解 // 原生ajax // 1. 创建ajax对象 if(window.XMLHttpRequest){ // // IE7+, Firefox, Chrome, Opera, S ...

  10. Eclipse、MinGW、JNI编写C++生成dll, Java端调用的完整示例(附java.lang.UnsatisfiedLinkError解决方法)

     Eclipse.MinGW.JNI编写C++生成dll, Java端调用的完整示例(附java.lang.UnsatisfiedLinkError解决方法) 问题背景:之前的JNI编程都是基于And ...