c++模板类的使用,编译的问题

前两天在写代码时,把模板类的声明和分开放在两个文件中了,类似于下面这样:

stack.hpp:

#ifndef _STACK_HPP
#define _STACK_HPP

template
class stack {
    public:
            stack();
            ~stack();
};
#endif

stack.cpp:

#include <iostream>
#include "stack.hpp"

template <typename type> stack<type>::stack() {
        std::cerr << "Hello, stack " << this << "!" << std::endl;
}

template <typename type> stack<type>::~stack() {
        std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
</type></typename></type></typename></iostream>

main.cpp

#include "stack.hpp"

int main() {
    stack s;

    return 0;
}
$ g++ -c -o main.o main.cpp
$ g++ -c -o stack.o stack.cpp
$ g++ -o main main.o stack.o
main.o: In function `main':
main.cpp:(.text+0xe): undefined reference to 'stack::stack()'
main.cpp:(.text+0x1c): undefined reference to 'stack::~stack()'
collect2: ld returned 1 exit status
make: *** [program] Error 1

提示找不到函数的定义

在网上寻找的答案如下:

It is not possible to write the implementation of a template class in a separate cpp file and compile. All the ways to do so, if anyone claims, are workarounds to mimic the usage of separate cpp file but practically if you intend to write a template class library and distribute it with header and lib files to hide the implementation, it is simply not possible.

To know why, let us look at the compilation process. The header files are never compiled. They are only preprocessed. The preprocessed code is then clubbed with the cpp file which is actually compiled. Now if the compiler has to generate the appropriate memory layout for the object it needs to know the data type of the template class.

Actually it must be understood that template class is not a class at all but a template for a class the declaration and definition of which is generated by the compiler at compile time after getting the information of the data type from the argument. As long as the memory layout cannot be created, the instructions for the method definition cannot be generated. Remember the first argument of the class method is the ‘this’ operator. All class methods are converted into individual methods with name mangling and the first parameter as the object which it operates on. The ‘this’ argument is which actually tells about size of the object which incase of template class is unavailable for the compiler unless the user instantiates the object with a valid type argument. In this case if you put the method definitions in a separate cpp file and try to compile it the object file itself will not be generated with the class information. The compilation will not fail, it would generate the object file but it won’t generate any code for the template class in the object file. This is the reason why the linker is unable to find the symbols in the object files and the build fails.

Now what is the alternative to hide important implementation details? As we all know the main objective behind separating interface from implementation is hiding implementation details in binary form. This is where you must separate the data structures and algorithms. Your template classes must represent only data structures not the algorithms. This enables you to hide more valuable implementation details in separate non-templatized class libraries, the classes inside which would work on the template classes or just use them to hold data. The template class would actually contain less code to assign, get and set data. Rest of the work would be done by the algorithm classes.

具体原因就是:

模板类其实就不是一个类,c++的编译器在编译.cpp产生二进制目标文件的时候,需要根据函数的参数类型来确定链接符号(编译器不编译.h文件),而编译模板类的时候因为函数的参数类型都没有确定,所以也就不能产生链接符号,所以在编译阶段是不会报错的,但是在链接阶段就报错了。针对这种情况有三种解决办法,但是最优的还是把实现和声明都放在头文件中。如果不想让c++类显得臃肿,可以在类里面声明,在类外进行实现。

参考链接

Original: https://www.cnblogs.com/xutopia/p/15715756.html
Author: xutopia
Title: c++模板类的使用,编译的问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/611220/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • K8S部署之VMWare网络拓扑踩坑

    知乎上最近发现一篇好文 图解K8S(01):基于Ubuntu 20.04部署1.23版K8S集群,想着之前 K8S 部署一直不成功,那么就照着这篇文章中说的试一试。结果在实验时遇到…

    Linux 2023年5月27日
    094
  • CSS解决父级边框坍塌的问题

    首先在父级标签内添加如下 标签 然后在CSS中对该标签进行如下修饰: #clear{ clear:both; margin:0px; padding: 0px; } 优点:简单。缺…

    Linux 2023年6月13日
    0102
  • 在VS code使用Remote-SSH远程连接Linux 开发C++ 配置详细介绍

    VS code 远程连接服务器,编译C++ 一、前期准备 1、VS code安装 Remote-SSH插件 2、Windows安装SSH。 3、Linux服务器连接测试。 a.接通…

    Linux 2023年5月27日
    0158
  • Linux服务器下oracle数据库启动服务操作步骤

    一、在Linux下启动Oracle1.登录到Linux服务器,切换到oracle用户权限(命令是:# su –l oracle) 2.进入sqlplus界面(命令是:$ sqlpl…

    Linux 2023年6月13日
    0103
  • acl/客户端缓存/多级缓存

    redis6安装注意点 我们课程里忽略了,就不去安装了,仅仅只提供安装文档,redis6的安装其实和redis5安装差不多,只是需要注意gcc的版本需要提高,不然编译会出错。参考慕…

    Linux 2023年5月28日
    099
  • 用 Redis 做一个可靠的延迟队列

    抢先体验 本文的完整代码实现在hdt3213/delayqueue,可以直接使用 go get 安装: go get github.com/hdt3213/delayqueue 使…

    Linux 2023年5月28日
    0111
  • Apache Solr Velocity 注入远程命令执行漏洞 (CVE-2019-17558)

    一、Apache Solr介绍 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于web-service的API接口,用户可以通过http请求,向搜索引擎服务器提交一定格式…

    Linux 2023年6月13日
    098
  • short, int, long, long long各个类型的范围

    类型名称 字节数 取值范围 signed char 1 -2^7 ~ 2^7-1 -128~+127 short int 2 -2^14 ~ 2^14-1 -32768~+3276…

    Linux 2023年6月8日
    0113
  • redis持久化存储

    redis持久化存储 redis多被用于缓存和消息中间件,当被用作缓存时,数据的读写都是在内存中进行的,而内存一旦在主机断电或者主机重启时里面的数据将被清空,为保证数据不被丢失,r…

    Linux 2023年6月7日
    0113
  • 手把手教你在Linux系统下安装MongoDB

    1. 下载最新的stable版MongoDB [root@spirit-of-fire ~]# wget http://downloads.mongodb.org/linux/mo…

    Linux 2023年6月14日
    0141
  • Samba:文件共享

    samba:现主要用于Linux与Windows之间的文件共享。 samba的特点: 用于Linux与Windows之间进行文件共享和打印机共享 不仅用于Windows之间的文件共…

    Linux 2023年6月13日
    0115
  • go-结构体内存布局

    方式一:通过 var 声明结构体 在 Go 语言中当一个变量被声明的时候,系统会自动初始化它的默认值,比如 int 被初始化为 0,指针为 nil。 var 声明同样也会为结构体类…

    Linux 2023年6月13日
    0103
  • redis的事件处理机制

    redis的事件处理机制 redis是单进程,单线程模型,与nginx的多进程不同,与golang的多协程也不同,”工作的工人”那么少,可那么为什么redi…

    Linux 2023年5月28日
    0112
  • linux全新机器环境搭建流程梳理

    软件解压后安装基础指令(复制用):./configure && make && make install ./configure –pr…

    Linux 2023年6月6日
    090
  • 搭建openvpn连接公司内网

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    0123
  • ToneGenerator Init failed Crash 崩溃

    需求需要在扫码时产生一个短促的提示音, 搜了下像这样实现。测试时发现多次扫码后,会触发程序崩溃问题。 异常如下 代码如下: 一番搜索, 以下为最佳答案, 加上以后,循环测试, 不再…

    Linux 2023年6月13日
    0111
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球