编辑:当我将link_def.cpp与link_dec.h合并时,我只得到第一个错误,而不是第二个错误.
当我尝试编译一些代码时,我遇到了这些链接器错误:CODE:
#include"list_dec.h"
#include"catch.h"
int main()
{
list<int, 100> L1;
try
{
L1.return_current();
}
catch(err)
{
return -1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
错误:
Linking...
main.obj : error LNK2019: unresolved external symbol "public: __thiscall list<int,100>::~list<int,100>(void)" (??1?$list@H$0GE@@@QAE@XZ) referenced in function __catch$_main$0
main.obj : error LNK2019: unresolved external symbol "public: int __thiscall list<int,100>::return_current(void)" (?return_current@?$list@H$0GE@@@QAEHXZ) referenced in function _main
main.obj : error LNK2019: unresolved external symbol "public: __thiscall list<int,100>::list<int,100>(void)" (??0?$list@H$0GE@@@QAE@XZ) referenced in function _main
Run Code Online (Sandbox Code Playgroud)
如果有人需要list_dec.h,catch.h和list_def.cpp(列表类的定义)的代码,只需注释,我不想包含它们,如果它们是无关紧要的,因为它们非常大.
因为有人想看list_dec.h(我暂时与list_def.cpp合并)list_dec.h:
template<class T, size_t limit>
class list
{
public:
//constructors
list();
list(const list<T, limit>& lst);
~list();
//assignment operator
void operator=(const list<T, limit>& lst);
//append new items
void append(const T& item);
//clear the list
void clear();
//return current item
T return_current();
//test if item is last item
bool last();
//make current item head of the list
void make_head();
//move to the next item
bool next();
//interrogation
size_t return_count();
size_t return_limit();
protected:
size_t count; //# of items in list
size_t current; //current item
T data[limit]; //array of elements of list
//internal functions
void copy(const list<T, limit>& lst);
};
//copier function
template<class T, size_t limit>
void list<T, limit>::copy(const list<T, limit>& lst)
{
count = lst.count;
current = lst.current;
for(size_t n = 0; n < count; n++)
{
data[n] = lst.data[n];
}
return;
}
//constructor
template<class T, size_t limit>
inline list<T, limit>::list()
{
count = 0;
current = 0;
}
//copy constructor
template<class T, size_t limit>
inline list<T, limit>::list(const list<T, limit>& lst)
{
copy(lst);
}
//assignment operator
template<class T, size_t limit>
inline void list<T, limit>::operator=(const list<T, limit>& lst)
{
clear();
copy(lst);
return;
}
//destructor
template<class T, size_t limit>
inline list<T, limit>::~list()
{
clear();
}
//append function
template<class T, size_t limit>
void list<T, limit>::append(const T& item)
{
if(count == limit)
{
throw CX_OVERFLOW;
}
data[count] = item;
count++;
return;
}
//return current item
template<class T, size_t limit>
T list<T, limit>::return_current()
{
if(count == 0)
{
throw CX_NULL;
}
if(current == count)
{
throw CX_ATEND;
}
return data[current];
}
//test if <current> pointer is at tail
template<class T, size_t limit>
inline bool list<T, limit>::last()
{
if(current == count)
{
return true;
}
else
{
return false;
}
}
//set current pointer to head
template<class T, size_t limit>
inline void list<T, limit>::make_head()
{
current = 0;
return;
}
//set current pointer to next pointer in list
template<class T, size_t limit>
bool list<T, limit>::next()
{
if(count == 0)
{
throw CX_NULL;
}
if(current == count)
{
throw CX_ATEND;
}
current++;
if(current == count)
{
return false;
}
return true;
}
//interrogation functions
template<class T, size_t limit>
inline size_t list<T, limit>::return_count()
{
return count;
}
template<class T, size_t limit>
inline size_t list<T, limit>::return_limit()
{
return limit;
}
Run Code Online (Sandbox Code Playgroud)
jal*_*alf 10
可以通过一些努力来读取链接器错误.试一试吧:
main.obj : error LNK2019: unresolved external symbol "public: __thiscall list<int,100>::~list<int,100>(void)" (??1?$list@H$0GE@@@QAE@XZ) referenced in function __catch$_main$0
Run Code Online (Sandbox Code Playgroud)
main.obj,即从main.cpp生成的目标文件.list<int,100>::~list<int,100>(void)"来看一些非常有用的信息:告诉我们问题是类模板列表的析构函数,专门用于<int, 100>.这部分格式很好,非常简单.对于第二个错误,我们也看到了返回类型:int __thiscall list<int,100>::return_current(void).也就是说,一个返回int的函数,使用__thiscall调用约定,属于list,被称为return_current,并且不带参数.??1?$list@H$0GE@@@QAE@XZ几乎可以被忽略.这是编译器损坏的符号名称,因此这是链接器在.obj文件中查找的名称.但由于链接器已经告诉我们符号的可读C++名称,我们并不需要这个.(除非你决定自己去挖掘.obj文件).所以你有它.第一个错误表明无法找到列表析构函数的定义.如果函数未在类定义中声明为内联,则应在另一个.cpp文件中定义.我假设这是你的list_def.cpp,并且该文件也被编译并传递给链接器.
然而,这导致我们对模板的一个小问题.它们是编译时构造,并且必须在编译器为其发出代码之前实例化模板.在编译器的输出中,类模板list和特化都不存在代码list<int, 84>,因为不使用该特化.编译器仅生成实际需要的特化.
当编译器处理list_def.cpp,没有特似乎是必需的.它无法看到其他.cpp文件,例如main.cpp.它只看到当前正在编译的.cpp文件,以及它#include的任何内容.由于它无法看到list<int, 100>,它不会为该特化生成任何代码,然后当目标文件传递给链接器时,它无法找到list<int, 100>符号的定义并发出错误.
通常的解决方案是在标题中内联定义类模板的所有成员.这样,该定义对包括头部在内的任何编译单元都是可见的,因此编译器可以创建所需的模板特化.
具体来说,以下将产生链接器错误:
// .h
template <int n>
class Foo {
int Bar();
};
// .cpp
template <int n>
int Foo::Bar() {
return n; // Error: This is not visible from other .cpp files
}
Run Code Online (Sandbox Code Playgroud)
因此,只需将.cpp内容移动到标题中:
// .h
template <int n>
class Foo {
int Bar();
};
template <int n>
int Foo::Bar() {
return n; // Error: This is will cause the function to be defined in every .cpp file that includes it, so you'll get a *different* linker error instead (multiple definitions)
}
Run Code Online (Sandbox Code Playgroud)
但这是有效的,也是通常的解决方案
// .h
template <int n>
class Foo {
int Bar() { return n; } // just define it here, inside the class definition, and it is implicitly inline, so it's ok that multiple .cpp files see it
};
Run Code Online (Sandbox Code Playgroud)
或者:
// .h
template <int n>
class Foo {
int Bar();
};
// still in .h
template <int n>
inline int Foo::Bar() { // explicitly marking it inline works too. Now the compiler knows that it might be defined in multiple .cpp files, and these definitions should be merged back together
return n;
}
Run Code Online (Sandbox Code Playgroud)
更不寻常但偶尔有用的解决方案是在定义它的编译单元中显式实例化模板.所以list_def.cpp,在模板定义之后添加这一行:
template class list<int, 100>;
Run Code Online (Sandbox Code Playgroud)
这告诉编译器专门为该特化生成代码,即使它没有在此编译单元中使用.显然,只有事先知道需要哪些专业化,这种方法才有用.
编辑:
看起来你永远不会定义clear()从析构函数调用的函数.这就是在包含标题中的所有内容后出现最终链接器错误的原因.