我们首先从一个问题来阐明类的底层机理:
假如有一个类A,里面有一个成员函数get(),例如:
class A
{
public:
    void get();
}
A a;
那么a.get()表示什么呢?首先给出答案是get(&a),因为在类的底层机制中,成员函数的第一个参数都是一个指向该类数据结构的指针(静态成员函数除外),所以成员函数get()的存在形式为void get(A* this);这也能说明为什么我们在成员函数的定义中总是可以用this来指代调用对象。
我们知道,要使用一个C++类,必要的条件是在编译期能得到这个类的头文件,并在链接期可以找到对应的符号的链接地址(比如成员函数、静态数据成员等)。如果这个C++类与你的使用者在同一个工程,那这个条件很好满足:
首先,C++类的头文件很好获得。直接在使用者那里将类的头文件include即可;
其次,C++类往往被编译器作为一个编译单元,生成一个obj文件。在最后进行链接的过程中,链接器会把工程中所有的obj链接以生成最终的二进制目标文件。所以链接器在遇到一处对类成员函数(或其它形式的符号引用)时,会在这个类生成的obj文件中找到符号的链接地址。
那么,在代码中使用一个C++类,编译期和链接期需要的到底是些什么东西呢?换句话说,满足了什么样的条件,编译器和链接器就不会抱怨了呢?
根据C++语言的定义,一个C++类实际上是声明或定义了如下几类内容:
1.声明了一个数据结构,类中的非静态数据成员、代码中看不到但如果有虚函数就会生成的虚表入口地址指针等。
2.声明并定义了一堆函数,它们第一个参数都是一个指向这个数据结构的指针。这些实际上就是类中那些非静态成员函数(包括虚函数),它们虽然在类声明中是写在类的一对大括号内部,但实际上没有任何东西被加到前面第1条中所说的内部数据结构中。实际上,这样的声明只是为这些函数增加了两个属性:函数名标识符的作用域被限制在类中;函数第一个参数是this,被省略不写了。
3.声明并定义了另一堆函数,它们看上去就是一些普通函数,与这个类几乎没有关系。这些实际上就是类中那些静态函数,它们也是一样,不会在第1条中所说的内部数据结构中增加什么东西,只是函数名标识符的作用域被限制在类中。
4.声明并定义了一堆全局变量。这些实际上就是类中那些静态数据成员。
5.声明并定义了一个全局变量,此全局变量是一个函数指针数组,用来保存此类中所有的虚函数的入口地址。当然,这个全局变量生成的前提是这个类有虚函数。
看下面的一个例子:
class MyClass
{
public:
    int x;
    int y;
    void Foo();
    void Bar(int newX, int newY);
    virtual void VFoo();
    virtual void VBar(int newX, int newY) = 0;
    static void SFoo();
    static void SBar(int newX, int newY);
    static int sx;
    static int sy;
};
对于上面列出的这个类MyClass,C++编译器多数会以如下的方式进行编译:
现在我们再来看一下为什么编译器需要头文件和符号地址就可以编译链接一个使用MyClass的程序了。
首先,由于编译器需要在编译期就知道类的内存布局,以保证可以生成正确的开辟内存的代码,及那些
sizeof(MyClass)的值。有了头文件,编译器就知道,一个MyClass占用12字节的内存空间(见上图,两个整数和一
个指针)。
其次,在调用MyClass的成员函数、静态函数时,链接器需要知道这些函数的入口地址,如果无法提供入口地址,
链接器就会报错。
最后,在引用MyClass的静态数据成员时,实际上与引用一个外部全局对象一样,链接器需要知道这些变量的地址。
如果无法提供这些变量的地址,链接器也会报错。
可以看出:
1. 编译期:必须要提供的是类的头文件,以使编译器可以得知类实例的尺寸和内存布局。
2. 链接期:必须要提供的是程序中引用过的,类的成员函数、静态函数、静态数据成员的地址,以使链接器可以正确的生成最终程序。
到这里,我们可以猜到,实际上,导出一个类,编译器实际上只需要将这个类中的:成员函数、静态函数、静态数
据成员当成普通的函数、全局变量导出即可。也就是说,我们实际上没有“导出一个类”,而是把这个类中需要被
引用的“有定义的实体”的入口地址像普通函数和变量那样正常导出即可。由于里面的纯虚函数VBar没有
定义,所以不会被导出。

C++类的底层机理的更多相关文章

  1. 为什么很多类甚者底层源码要implements Serializable ?

    为什么很多类甚者底层源码要implements Serializable ? 在碰到异常类RuntimeException时,发现Throwable实现了 Serializable,还有我们平进的ja ...

  2. 集合各个实现类的底层实现原理 ----- 原文地址:https://blog.csdn.net/qq_25868207/article/details/55259978

    ArrayList实现原理要点概括 参考文献: http://zhangshixi.iteye.com/blog/674856l https://www.cnblogs.com/leesf456/p/ ...

  3. JDK 1.8 sun.misc.Unsafe类CAS底层实现

    在java.util.concurrent包下面的很多类为了追求性能都采用了sun.misc.Unsafe类中的CAS操作,从而避免使用synchronized等加锁方式带来性能上的不足. 在sun. ...

  4. HibernateDaoSupport类的底层中hql操作使用

    spring的ApplicationContex.xml 中配置 sql 查询方法: 加载数据源的两种方式: <!--方式一:使用 c3p0 连接池 加载数据源 --> <bean ...

  5. C++ 学习资料搜寻与学习(第一期)(未完待续)

    一.图形图像类 [Visual C++]vs2008/2005正确打开vs2010所创建项目的几种方法 jlins 2012-04-12 14:38 [Visual C++]关于无法打开包括文件:“S ...

  6. Java中集合框架,Collection接口、Set接口、List接口、Map接口,已经常用的它们的实现类,简单的JDK源码分析底层实现

    (一)集合框架: Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(实现接口的类).所有抽象出来的数据结构和操作(算法)统称为集合框架. 程序员在具体应用的时候,不必考虑数据结构和 ...

  7. Kotlin数据类深度解析与底层剖析

    今天来学习一下全新关于Kotlin的概念---数据类[data class],也是非常有用的东东,下面先来对其进行理论化的了解: 数据类其实跟java的实体类(model)很类似,像Java定义一个P ...

  8. @dynamic 模拟NSManagedObject类的内部实现,AFN的非常规用法

    @property和@synthesize复习 @property生成setter和getter的声明,同时生成属性对应的成员变量,并且前面加一个下划线_.如果将getter和setter的实现同时重 ...

  9. Java API —— ArrayList类 & Vector类 & LinkList类

    1.ArrayList类     1)ArrayList类概述         · 底层数据结构是数组,查询快,增删慢         · 线程不安全,效率高     2)ArrayList案例   ...

随机推荐

  1. linux学习之——学习路线(摘抄)

    摘抄某笔者的Linux练习的道路图(rolistingmap): 对比一下为什么要学习linux 了解Linux的基础常识,这些包括了用户管理.群组的概念.权限的观念等 掌握至多50个以上的常用命令 ...

  2. WPF 获得鼠标相对于屏幕的位置,相对于控件的位置

    相对于屏幕的位置 第一步: /// <summary>    /// 用于获得鼠标相对于屏幕的位置    /// </summary>    public class Win3 ...

  3. PHP 输出缓冲控制(Output Control) 学习

    php 缓冲简介 其实我对php ob 系列印象还是很模糊,具体怎么玩的,还不是很了解,平时curd,确实对这些内容没有深入.作为phper 甚是惭愧.网上搜了一通,互相copy,代码运行不能出现作者 ...

  4. AIX网络性能优化简介

    在AIX 中,网络性能的优化可从以下几方面进行: 网络内存(network memory)的调整 socket 缓冲区 (socket buffer) 的调整 网络接口(network interfa ...

  5. vnc 登录后只有终端 没有桌面 黑屏

    1, start vnc server: vncserver :1 issue: connect it with pc and only display one terminal. 2, stop v ...

  6. 关于iphone、安卓手机VPN全面解析

    现在智能手机功能越来越强大,网络APP层出不穷,社交大佬facebook.twitter等纷纷推出了自己的社交APP应用,大部分手机已经内置了很多社交应用,包括facebook等:android.io ...

  7. js-BOM之offset家族、移动函数的封装升级(轮播图)

    Obj.style.width/obj.style.height与obj.offsetWidth/obj.offsetHeight的区别: <style> #div1{ height: 2 ...

  8. 【动态规划】bzoj1669 [Usaco2006 Oct]Hungry Cows饥饿的奶牛

    #include<cstdio> #include<algorithm> using namespace std; int n,a[5001],b[5001],en; int ...

  9. javascript中闭包的概念

    这个是每个前端工程师绕不开的一个问题,网上各种资料很多,整个春节,我仔细研读了红皮经典中关于这一块的注释,加深了对这一块的理解. 有好几个概念需要重申一下.以下都是我的理解: 1. 闭包是javasc ...

  10. WordPaster-Chrome浏览器控件安装方法

    将WordPaster.crx拖到Chrome扩展面板中安装