- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
这个问题在这里已经有了答案:
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
}
然后是队列模板类及其功能的定义和声明:
#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;
}
}
然后,我有一个程序来测试这些功能,如下所示:
#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;
}
但是当我构建时,编译器会在模板类的每个实例中抛出错误:
最佳答案
这是 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
)使用模板类时都会包含该头文件。 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
中。文件(即一个翻译单元),并且显式实例化放置在所有函数的定义之后(即在文件末尾)。
cola.cpp
和
nodo_colaypila.cpp
进入
cola.h
和
nodo_colaypila.h
.从长远来看,这更灵活,因为这意味着您可以使用额外的实例化(例如
cola<char>
)而无需更多工作。但这可能意味着相同的函数被编译多次,在每个翻译单元中编译一次。这不是什么大问题,因为链接器会正确地忽略重复的实现。但它可能会稍微减慢编译速度。
cola<float>
和
cola<string>
,如果您想要使用其他东西,请先告诉我,然后可以在启用它之前验证它是否有效。”)。
#endif
在 nodo_colaypila.h 末尾 nodo_colaypila<T>* ult, pri;
应该是 nodo_colaypila<T> *ult, *pri;
- 两者都是指针。 nodo_colaypila.h
中,不在这个实现文件中。 关于c++ - "Undefined reference to"模板类构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8752837/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!