zoukankan      html  css  js  c++  java
  • 关于C++编译链接和模板函数

    一,关于编译链接
    编译指的的把编译单元生成目标文件的过程

    链接是把目标文件链接到一起的过程

    编译单元:可以认为是一个.c或者.cpp文件。每个编译单元经过预处理会得到一个临时的编译单元。预处理会间接包含其他文件还会展开宏调用。

    每个编译单元编译成目标文件后会暴露自己内部的符号。
    (比如有个fun函数,就会暴露出于fun函数对应的符号,其他的函数和变量也是一样的。但是也有不会暴露出去的,比如加了static修饰的函数或变量)
    每个目标文件都有自己的符号导入表和符号导出表。


    链接器根据自己所需要的符号去找其他的目标文件。
    (假如main用到了别的文件定义发fun函数,在链接的过程中,链接器知道mian需要fun符号,然后去其他的目标文件总找。如果找到了就链接起来。找不到就报链接错误)

    二、模板函数
    模板函数的代码并不能直接编译成二进制代码,其中要有一个实例化的过程。模板被用到的时候才会进行实例化。

    1.假设有个test.h里面声明了模板函数。
    test.cpp实现了那个模板函数。
    main用到了那个模板函数。
    编译器会编译test.cpp编译单元和main.cpp编译单元。
    编译test.cpp时无法给出A<int>::fun这样的符号
    main.cpp需要一个这样的符号A<int>::fun。

    在分离式编译的环境下,编译器编译某个cpp文件时并不知道另外的cpp的存在,也不会去查找(当遇到未决符号时他会寄希望于链接器)。
    这种模式在没有模板的情况下运行良好,但是遇到模板时就不行了,因为模板仅在需要的时候才会实例化出来。
    所以当编译器只看到模板的声明时,它不能实例化该模板,只能创建一个具有外部连接的符号,并期待链接器能够将符号的地址决议找出来。
    然而实现该模板的cpp文件并没有用到该模板时,编译器就不会去实例化。
    所以整个工程当中找不到模板实例的代码,链接器就找不到那个符号。就会报错了。

    3.实例:
    test.h

    #ifndef __CAR_H__
    #define __CAR_H__
    #include<iostream>
    using namespace std;
    #define IN_CPP 1
    template <class T>
    class car
    {
    public:
        car(T a);
        void print();
    public:
        T data;
    };
    #if IN_CPP
    #else
    template <class T>
    car<T>::car(T a)
    {
        data = a;
    }
    template <class T>
    void car<T>::print()
    {
        cout << "data = " << data << endl;
    }
    #endif
    #endif // __CAR_H__

    test.cpp

    #include "car.h"
    #if IN_CPP
    template <class T>
    car<T>::car(T a)
    {
        data = a;
    }
    template <class T>
    void car<T>::print()
    {
        cout << "data = " << data << endl;
    }
    #endif
    void callTest()
    {
        car<int> a(33);
        a.print();
    }

    main.cpp

    #include<iostream>
    #include "car.h"
    using namespace std;
    void fun()
    {
        cout << "fun() +++" << endl;
        car<int> a(99);
        a.print();
    }
    int main()
    {
        fun();
        return 0;
    }

    分析:

    IN_CPP 如果是0:就相当于声明实现都在头文件中。这样main.cpp是可以编译运行的。
    IN_CPP 如果是1:说明声明跟实现分开了。这种情况main.cpp链接时找不到 car构造相关的函数,也找不到模板类car中print的函数。会报两个链接错。
    但是如果在test.cpp写个函数(callTest())调用car的构造和print,相当于实例化了那两个类模板函数。就会导出那两个函数的符号。假如只调用一个构造,那么print就没有实例化。main也会链接失败
    然后在main.cpp就可以调用到了。

  • 相关阅读:
    创建视图与触发器
    Ubuntu 安装JDK
    Ubuntu maven 配置
    Ubuntu Navicat for MySQL安装以及破解方案
    jquery input 选择器
    eclipse maven编译项目
    Eclipse @override报错
    jQuery Ajax 实例 ($.ajax、$.post、$.get)
    如何防止表单重复提交(转)
    用bit字段来判断性别等
  • 原文地址:https://www.cnblogs.com/xcywt/p/8039574.html
Copyright © 2011-2022 走看看