关于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();
a.print();
}
main.cpp
#include<iostream>
#include "car.h"
using namespace std;
void fun()
{
cout << "fun() +++" << endl;
car<int> a();
a.print();
}
int main()
{
fun();
return ;
}
分析:
IN_CPP 如果是0:就相当于声明实现都在头文件中。这样main.cpp是可以编译运行的。
IN_CPP 如果是1:说明声明跟实现分开了。这种情况main.cpp链接时找不到 car构造相关的函数,也找不到模板类car中print的函数。会报两个链接错。
但是如果在test.cpp写个函数(callTest())调用car的构造和print,相当于实例化了那两个类模板函数。就会导出那两个函数的符号。假如只调用一个构造,那么print就没有实例化。main也会链接失败
然后在main.cpp就可以调用到了。
关于C++编译链接和模板函数的更多相关文章
- 模板函数(template function)出现编译链接错误(link error)之解析
总的结论: 将template function 或者 template class的完整定义直接放在.h文件中,然后加到要使用这些template function的.cpp文件中. 1. 现 ...
- c++模板函数声明定义分离编译错误详解
今天看到accelerated c++上有个简单的vector容器的实现Vec,就再vs2008上编译了下: ///// Vec.h #ifndef GUARD_VEC_H #define GUARD ...
- 为什么模板函数的声明和实现都放在.h文件中
当你不使用这个模板函数或模板类,编译器并不实例化它,当你使用时,编译器需要实例化它,因为编译器是一次只能处理一个编译单元,也就是一次处理一个cpp文件,所以实例化时需要看到该模板的完整定义.所以都放在 ...
- C++ 模板的编译 以及 类模板内部的实例化
在C++中.编译器在看到模板的定义的时候.并不马上产生代码,仅仅有在看到用到模板时,比方调用了模板函数 或者 定义了类模板的 对象的时候.编译器才产生特定类型的代码. 一般而言,在调用函数的时候,仅仅 ...
- C++基础 (8) 第八天 数组指针 模板指针 C语言中的多态 模板函数
1昨日回顾 2 多态的练习-圆的图形 3多态的练习-程序员薪资 4员工管理案例-抽象类和技术员工的实现 employee.h: employee.cpp: technician.h: technici ...
- 使用 c++ 模板显示实例化解决模板函数声明与实现分离的问题
问题背景 开始正文之前,做一些背景铺垫,方便读者了解我的工程需求.我的项目是一个客户端消息分发中心,在连接上消息后台后,后台会不定时的给我推送一些消息,我再将它们转发给本机的其它桌面产品去做显示.后台 ...
- C++模板编程:如何使非通用的模板函数实现声明和定义分离
我们在编写C++类库时,为了隐藏实现,往往只能忍痛舍弃模版的强大特性.但如果我们只需要有限的几个类型的模版实现,并且不允许用户传入其他类型时,我们就可以将实例化的代码放在cpp文件中实现了.然而,当我 ...
- 加快XCode的编译链接速度(200%+)—XCode编译速度慢的解决方案
最近在开发一个大项目的时候遇到一个很头疼的问题,由于项目代码较多,每次都要编译链接1分钟左右,调试的时候很浪费时间,于是研究了一下如何提高编译链接的速度,在这里分享给大家. 提升编译链接的速度主要有以 ...
- C++开始前篇,深入编译链接(3)
一,COMMON块 什么是COMMON块,这是一种机制,早期的Fortran没有动态分配空间的机制,程序员必须事先声明它所需要的临时使用空间的大小.Fortran把这种空间叫做COMMON块,当不同的 ...
随机推荐
- virualbox 安装 otter 必备软件
前言 最近研究了一下阿里otter项目(分布式数据库同步),所以就在virualbox 上开始准备学习一下,遇到了不少坑,所以记录一下啊. otter 项目:https://github.com/al ...
- javascript中的变量、作用域和内存问题
1.变量 变量的值的类型:基本类型值和引用类型值两种. 基本类型:Undefined.Null.Boolean.String.Number,这五类基本数据类型的值在内存中占有固定大小的空间,因此保存在 ...
- vsftpd安装及虚拟用户配置
服务器环境:CentOS6.9 Linux 2.6.32-696.10.1.el6.x86_64 安装vsftpd.db4.db4-utils # yum -y install vsftpd db4 ...
- SQL Server 审计
审计(Audit)用于追踪和记录SQL Server实例或数据库中发生的事件,审计主要包括审计对象(Audit)和审计规范(Audit Specification),创建审计首先需要创建一个SQL S ...
- Mybatis整理_01
Mybatis专题 Mybaits介绍 Mybatis是一个持久化框架,它有不同语言的版本,比如.NET和Java都有Mybatis对应的类库:它有大多数ORM框架都具有的功能,比如自定义的SQL语句 ...
- 实现一个websocket服务器-理论篇
本文是Writing WebSocket servers的中文文档,翻译自MDNWriting WebSocket servers.篇幅略长,个人能力有限难免有所错误,抛砖引玉共同进步. websoc ...
- JavaScript面向对象(收集整理)
(1)封装 首先理解构造函数:所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量.对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上. f ...
- 你是如何自学 Python 的?
作为一名Python爱好者,我也想跟大家分享分享我自学Python的一些小经验.搬来你的小板凳,听听看吧.也许,你会很有收获,也许你也走上了自学Python的不归路.开讲啦~ 首先,你要有自信心,要明 ...
- 使用git命令将本地项目上传到Gitlab上
1.首先需要安装本地需要安装git 2.在gitlab上创建项目, 如下图, 点击右上角加号到项目创建页面, 填写项目名称, 选择项目访问权限, private为授权的组员才能访问. 3.打开项目源代 ...
- JQuery使用笔记
1.选择器 id选择器: $('#btnShow') class选择器: $('.banner') tag选择器: $('input') 2.常用方法 取 / 设value: $('#btnShow' ...