問題描述
我在嘗試編譯一個 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
當(dāng)然是正確的:符號不在 stack.o
中.
ld
is of course correct: the symbols aren't in stack.o
.
這個問題的答案沒有幫助,因?yàn)槲乙呀?jīng)按照它說的做了.
這個可能有幫助,但我不想移動每一個方法進(jìn)入 .hpp
文件—我不應(yīng)該這樣做,是嗎?
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
文件中的所有內(nèi)容移動到 .hpp
文件中的唯一合理解決方案,并且簡單地包含所有內(nèi)容,而不是作為獨(dú)立對象文件鏈接?這看起來非常丑陋!在這種情況下,我不妨恢復(fù)到我以前的狀態(tài)并將 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.
推薦答案
無法在單獨(dú)的 cpp 文件中編寫模板類的實(shí)現(xiàn)并進(jìn)行編譯.如果有人聲稱,所有這樣做的方法都是模仿單獨(dú) cpp 文件使用的變通方法,但實(shí)際上,如果您打算編寫模板類庫并將其與頭文件和 lib 文件一起分發(fā)以隱藏實(shí)現(xiàn),這是不可能的.
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.
要知道為什么,讓我們看看編譯過程.頭文件永遠(yuǎn)不會被編譯.它們只是經(jīng)過預(yù)處理.然后將預(yù)處理的代碼與實(shí)際編譯的 cpp 文件結(jié)合在一起.現(xiàn)在,如果編譯器必須為對象生成適當(dāng)?shù)膬?nèi)存布局,則它需要知道模板類的數(shù)據(jù)類型.
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.
其實(shí)要明白,模板類根本就不是一個類,而是一個類的模板,它的聲明和定義是編譯器在編譯時從參數(shù)中得到數(shù)據(jù)類型的信息后生成的.只要無法創(chuàng)建內(nèi)存布局,就無法生成方法定義的指令.記住類方法的第一個參數(shù)是this"運(yùn)算符.所有類方法都被轉(zhuǎn)換為具有名稱修飾和第一個參數(shù)作為其操作對象的單獨(dú)方法.'this' 參數(shù)實(shí)際上說明了對象的大小,除非用戶使用有效的類型參數(shù)實(shí)例化對象,否則編譯器無法使用模板類.在這種情況下,如果您將方法定義放在單獨(dú)的 cpp 文件中并嘗試編譯它,則不會生成帶有類信息的目標(biāo)文件本身.編譯不會失敗,它會生成目標(biāo)文件,但不會為目標(biāo)文件中的模板類生成任何代碼.這就是鏈接器無法在目標(biāo)文件中找到符號并且構(gòu)建失敗的原因.
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.
現(xiàn)在隱藏重要實(shí)現(xiàn)細(xì)節(jié)的替代方法是什么?眾所周知,將接口與實(shí)現(xiàn)分離的主要目的是以二進(jìn)制形式隱藏實(shí)現(xiàn)細(xì)節(jié).這是您必須分離數(shù)據(jù)結(jié)構(gòu)和算法的地方.您的模板類必須僅表示數(shù)據(jù)結(jié)構(gòu),而不是算法.這使您能夠在單獨(dú)的非模板化類庫中隱藏更有價(jià)值的實(shí)現(xiàn)細(xì)節(jié),其中的類可以在模板類上工作或僅使用它們來保存數(shù)據(jù).模板類實(shí)際上包含更少的代碼來分配、獲取和設(shè)置數(shù)據(jù).其余的工作將由算法類完成.
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.
這篇關(guān)于將模板化的 C++ 類拆分為 .hpp/.cpp 文件——這可能嗎?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!