gpt4 book ai didi

c++ - "Undefined reference to"模板类构造函数

转载 作者:IT老高 更新时间:2023-10-28 11:33:42 32 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





Why can templates only be implemented in the header file?

(17 个回答)


6年前关闭。




我不知道为什么会发生这种情况,因为我认为我已经正确声明和定义了所有内容。
我有以下程序,用模板设计。这是一个队列的简单实现,具有成员函数“add”、“substract”和“print”。
我在“nodo_colaypila.h”中定义了队列的节点:

#ifndef NODO_COLAYPILA_H
#define NODO_COLAYPILA_H

#include <iostream>

template <class T> class cola;

template <class T> class nodo_colaypila
{
T elem;
nodo_colaypila<T>* sig;
friend class cola<T>;
public:
nodo_colaypila(T, nodo_colaypila<T>*);

};
然后在“nodo_colaypila.cpp”中实现
#include "nodo_colaypila.h"
#include <iostream>

template <class T> nodo_colaypila<T>::nodo_colaypila(T a, nodo_colaypila<T>* siguiente = NULL)
{
elem = a;
sig = siguiente;//ctor
}
然后是队列模板类及其功能的定义和声明:
“可乐.h”:
#ifndef COLA_H
#define COLA_H

#include "nodo_colaypila.h"

template <class T> class cola
{
nodo_colaypila<T>* ult, pri;
public:
cola<T>();
void anade(T&);
T saca();
void print() const;
virtual ~cola();

};


#endif // COLA_H
“可乐.cpp”:
#include "cola.h"
#include "nodo_colaypila.h"

#include <iostream>

using namespace std;

template <class T> cola<T>::cola()
{
pri = NULL;
ult = NULL;//ctor
}

template <class T> void cola<T>::anade(T& valor)
{
nodo_colaypila <T> * nuevo;

if (ult)
{
nuevo = new nodo_colaypila<T> (valor);
ult->sig = nuevo;
ult = nuevo;
}
if (!pri)
{
pri = nuevo;
}
}

template <class T> T cola<T>::saca()
{
nodo_colaypila <T> * aux;
T valor;

aux = pri;
if (!aux)
{
return 0;
}
pri = aux->sig;
valor = aux->elem;
delete aux;
if(!pri)
{
ult = NULL;
}
return valor;
}

template <class T> cola<T>::~cola()
{
while(pri)
{
saca();
}//dtor
}

template <class T> void cola<T>::print() const
{
nodo_colaypila <T> * aux;
aux = pri;
while(aux)
{
cout << aux->elem << endl;
aux = aux->sig;
}
}
然后,我有一个程序来测试这些功能,如下所示:
“主.cpp”
#include <iostream>
#include "cola.h"
#include "nodo_colaypila.h"

using namespace std;

int main()
{
float a, b, c;
string d, e, f;
cola<float> flo;
cola<string> str;

a = 3.14;
b = 2.71;
c = 6.02;
flo.anade(a);
flo.anade(b);
flo.anade(c);
flo.print();
cout << endl;

d = "John";
e = "Mark";
f = "Matthew";
str.anade(d);
str.anade(e);
str.anade(f);
cout << endl;

c = flo.saca();
cout << "First In First Out Float: " << c << endl;
cout << endl;

f = str.saca();
cout << "First In First Out String: " << f << endl;
cout << endl;

flo.print();
cout << endl;
str.print();

cout << "Hello world!" << endl;
return 0;
}
但是当我构建时,编译器会在模板类的每个实例中抛出错误:
对 `cola(float)::cola()' 的 undefined reference ... (它实际上是可乐'<'float'>'::cola(),但这不允许我那样使用它。)
等等。总共 17 个警告,包括程序中调用的成员函数的警告。
这是为什么?这些函数和构造函数是定义好的。我认为编译器可以用“float”、“string”或其他任何东西替换模板中的“T”;这就是使用模板的优势。
我在这里读到,出于某种原因,我应该将每个函数的声明放在头文件中。是吗?如果是这样,为什么?

最佳答案

这是 C++ 编程中的常见问题。对此有两个有效的答案。两种答案各有利弊,您的选择将取决于上下文。常见的答案是将所有实现放在头文件中,但在某些情况下还有另一种方法适用。这是你的选择。

模板中的代码只是编译器已知的“模式”。编译器不会编译构造函数 cola<float>::cola(...)cola<string>::cola(...)直到它被迫这样做。并且我们必须确保在整个编译过程中至少对构造函数进行一次编译,否则我们将得到“ undefined reference ”错误。 (这也适用于 cola<T> 的其他方法。)

了解问题

问题是由 main.cpp 引起的和 cola.cpp将首先单独编译。在 main.cpp ,编译器会隐式实例化模板类 cola<float>cola<string>因为在 main.cpp 中使用了那些特定的实例化.坏消息是这些成员函数的实现不在 main.cpp 中。 ,也不在 main.cpp 中包含的任何头文件中,因此编译器不能在 main.o 中包含这些函数的完整版本。 .编译时cola.cpp ,编译器也不会编译这些实例化,因为没有隐式或显式实例化 cola<float>cola<string> .记住,编译时cola.cpp ,编译器不知道需要哪些实例化;我们不能指望它为每种类型编译以确保这个问题永远不会发生! ( cola<int> , cola<char> , cola<ostream> , cola< cola<int> > ... 等等...)

两个答案是:

  • 告诉编译器,在cola.cpp结尾,需要哪些特定的模板类,迫使它编译 cola<float>cola<string> .
  • 将成员函数的实现放在一个头文件中,每次任何其他“翻译单元”(例如 main.cpp)使用模板类时都会包含该头文件。

  • 答案 1:显式实例化模板及其成员定义

    cola.cpp ,您应该添加显式实例化所有相关模板的行,例如
    template class cola<float>;
    template class cola<string>;

    然后在 nodo_colaypila.cpp 的末尾添加以下两行:
    template class nodo_colaypila<float>;
    template class nodo_colaypila<std :: string>;

    这将确保,当编译器编译 cola.cpp 时它将显式编译 cola<float> 的所有代码和 cola<string>类。同样, nodo_colaypila.cpp包含 nodo_colaypila<...> 的实现类。

    在这种方法中,您应该确保所有的实现都放在一个 .cpp 中。文件(即一个翻译单元),并且显式实例化放置在所有函数的定义之后(即在文件末尾)。

    答案2:将代码复制到相关的头文件中

    常见的答案是移动实现文件中的所有代码 cola.cppnodo_colaypila.cpp进入 cola.hnodo_colaypila.h .从长远来看,这更灵活,因为这意味着您可以使用额外的实例化(例如 cola<char> )而无需更多工作。但这可能意味着相同的函数被编译多次,在每个翻译单元中编译一次。这不是什么大问题,因为链接器会正确地忽略重复的实现。但它可能会稍微减慢编译速度。

    概括

    例如,STL 使用的默认答案以及我们任何人将编写的大多数代码中的默认答案是将所有实现放在头文件中。但在一个更私密的项目中,您将拥有更多的知识和控制权,了解哪些特定的模板类将被实例化。事实上,这个“错误”可能被视为一项功能,因为它可以阻止您的代码用户意外使用您尚未测试或计划的实例化(“我知道这适用于 cola<float>cola<string> ,如果您想要使用其他东西,请先告诉我,然后可以在启用它之前验证它是否有效。”)。

    最后,您问题中的代码还有另外三个小错别字:
  • 您缺少一个 #endif在 nodo_colaypila.h 末尾
  • 在可乐.h nodo_colaypila<T>* ult, pri;应该是 nodo_colaypila<T> *ult, *pri; - 两者都是指针。
  • nodo_colaypila.cpp:默认参数应该在头文件nodo_colaypila.h中,不在这个实现文件中。
  • 关于c++ - "Undefined reference to"模板类构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8752837/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com