专栏首页xcywt关于C++编译链接和模板函数

关于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就可以调用到了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 《程序员的自我修养》第二章学习笔记

    第二章 编译和链接 2.1被隐藏了的过程 我们知道,一个程序由源代码到可执行文件往往由这几步构成: 预处理(Prepressing)-> 编译(Compilat...

    xcywt
  • 《Linux命令行与shell脚本编程大全》 第五章理解shell

    5.1 1. cat /etc/passwd 可以查看每个用户自己的默认的shell程序。 2.默认的交互shell会在用户登录某个虚拟控制台终端时启动。 不过...

    xcywt
  • 前三章 man手册 查看文件

    1 – 3章 1.1 man手册: 分1 - 9个区域,可以认为是一个一个小节 把man手册理解为一本书 第一节:可执行程序或shell命令 第二节:系统调用 ...

    xcywt
  • 如何在 Stack Overflow 规范提问

    最近学习js的时候看到了一段代码,思考再三之后仍然不是很理解,于是决定到尽可能多的平台进行提问,目的有二:1.最主要的,解决问题;2.借这个机会测试哪些平台可以...

    Chor
  • Linux基础(好用到流泪的awk)

    有些人刚学Linux,被各种字符界面的命令和工具所折磨,觉得还是点鼠标方便。但说到底其实都只是没有领略字符工具的效率和魅力罢了。Linux中不乏命令中的神器,今...

    用户2617681
  • 什么使DevOps中的代码审查良好?[DevOps]

    改善软件开发生命周期,向客户交付软件的速度以及该软件的质量都是DevOps的重要前提。这些是DevOps运动规定的工具和技术试图达到的目标。作为开发人员,感到很...

    yyx
  • Git 和 GitHub:从入门到实践1 Git 和 GitHub 基础简介

    原文地址:https://www.ibm.com/developerworks/cn/opensource/os-cn-git-and-github-1/ind...

    mafeifan
  • js和ts的相互调用

    一枚小工
  • Pandas缺失值处理 | 轻松玩转Pandas(3)

    禹都一只猫olei
  • Linux CMake 快速使用(一)

    缘起:之前给别人提供的SDK都是在Linux下使用Qt搭建的,但是最近有客户不使用Qt,而是需要在Linux下使用cmake进行进行文件组织。于是我就进行谷歌,...

    用户5908113

扫码关注云+社区

领取腾讯云代金券