将模板化的 C++ 类拆分为 .hpp/.cpp 文件――这可能吗?
我在尝试编译一个 C++ 模板类时出错,该类在 .hpp
和 .cpp
文件之间拆分:
I am getting errors trying to compile a C++ template class which is split between a .hpp
and .cpp
file:
$ 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<int>::stack()'
main.cpp:(.text+0x1c): undefined reference to 'stack<int>::~stack()'
collect2: ld returned 1 exit status
make: *** [program] Error 1
这是我的代码:
stack.hpp:
#ifndef _STACK_HPP
#define _STACK_HPP
template <typename Type>
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;
}
ma??in.cpp:
#include "stack.hpp"
int main() {
stack<int> s;
return 0;
}
ld
当然是正确的:符号不在 stack.o
中.
ld
is of course correct: the symbols aren't in stack.o
.
这个问题的答案没有帮助,因为我已经按照它说的做了.
这个可能有帮助,但我不想移动每一个方法进入 .hpp
文件—我不应该这样做,是吗?
The answer to this question does not help, as I'm already doing as it says.
This one might help, but I don't want to move every single method into the .hpp
file—I shouldn't have to, should I?
是将 .cpp
文件中的所有内容移动到 .hpp
文件中的唯一合理解决方案,并且简单地包含所有内容,而不是作为独立对象文件链接?这看起来非常丑陋!在这种情况下,我不妨恢复到我以前的状态并将 stack.cpp
重命名为 stack.hpp
并完成它.
Is the only reasonable solution to move everything in the .cpp
file to the .hpp
file, and simply include everything, rather than link in as a standalone object file? That seems awfully ugly! In that case, I might as well revert to my previous state and rename stack.cpp
to stack.hpp
and be done with it.
推荐答案
无法在单独的 cpp 文件中编写模板类的实现并进行编译.如果有人声称,所有这样做的方法都是模仿单独 cpp 文件使用的变通方法,但实际上,如果您打算编写模板类库并将其与头文件和 lib 文件一起分发以隐藏实现,这是不可能的.
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.
要知道为什么,让我们看看编译过程.头文件永远不会被编译.它们只是经过预处理.然后将预处理的代码与实际编译的 cpp 文件结合在一起.现在,如果编译器必须为对象生成适当的内存布局,则它需要知道模板类的数据类型.
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.
其实要明白,模板类根本就不是一个类,而是一个类的模板,它的声明和定义是编译器在编译时从参数中得到数据类型的信息后生成的.只要无法创建内存布局,就无法生成方法定义的指令.记住类方法的第一个参数是this"运算符.所有类方法都被转换为具有名称修饰和第一个参数作为其操作对象的单独方法.'this' 参数实际上说明了对象的大小,除非用户使用有效的类型参数实例化对象,否则编译器无法使用模板类.在这种情况下,如果您将方法定义放在单独的 cpp 文件中并尝试编译它,则不会生成带有类信息的目标文件本身.编译不会失败,它会生成目标文件,但不会为目标文件中的模板类生成任何代码.这就是链接器无法在目标文件中找到符号并且构建失败的原因.
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.
我希望这个讨论会有所帮助.
I hope this discussion would be helpful.
相关文章