• C++学习笔记(2)---2.5 C++函数编译原理和成员函数的实现


    转载自: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 可以确保新函数名的唯一性,只要命名空间、所属的类、参数签名等有一个不同,那么产生的新函数名也不同。

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

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


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

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


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

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

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

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

    成员函数的调用

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

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

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

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

    [cpp] view plain copy
     
    1. void Demo::display(){  
    2.     cout<<a<<endl;  
    3.     cout<<b<<endl;  
    4. }  


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

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


    调用时的形式类似于:

    [cpp] view plain copy
     
    1. new_function_name(&obj);  


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

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

  • 相关阅读:
    Search Insert Position(二分查找)
    c++基础题
    Divide Two Integers(模拟计算机除法)
    Swap Nodes in Pairs(链表操作)
    Letter Combinations of a Phone Number(带for循环的DFS,组合问题,递归总结)
    进程和程序的区别
    Add Two Numbers(链表)
    Longest Substring Without Repeating Characters
    02.友盟项目--原始日志数据生成
    01.友盟项目--nginx服务器配置
  • 原文地址:https://www.cnblogs.com/haoyul/p/7257688.html
Copyright © 2020-2023  润新知