模板类的定义与声明

论坛 期权论坛 脚本     
已经匿名di用户   2022-4-26 15:52   2858   0

写了一个模板类,类似其它类那样把定义与声明分开,结果发现只是引用.h文件根本找不到函数的定义。查看相关资料发现如下解释

  1. 模板是不是一个类或函数。 模板是一个“模式”,编译器用来生成的相似的或者函数
  2. 为了让编译器生成的代码,它必须同时看到模板的定义(不只是声明)和特定类型/任何用于“fill in”模板的类型。例如,如果你想使用一个foo<int>,编译器必须同时看到foo模板和你要调用具体的foo<int>。
  3. 编译器可能不记得另外一个.cpp文件的细节,当编译其他.cpp文件的时候。它可以 ,但大多数都没有,如果你正在阅读本FAQ,它几乎肯定不会。顺便说一句,这就是所谓的“独立编译模型”。

现在,基于这些事实,下面是一个范例,它表明为什么是这个样子。假设你有一个这样的模板Foo声明:

template<typename T>
class Foo {
public:
Foo();
void someMethod(T x);
private:
T x;
};

类似地,模板成员函数的定义:

template<typename T>
Foo<T>::Foo()
{
...
}

template<typename T>
void Foo<T>::someMethod(T x)
{
...
}

现在,假设在文件Bar.cpp的一些代码要使用foo<int>:

// Bar.cpp

void blah_blah_blah()
{
...
Foo<int> f;
f.someMethod(5);
...
}

显然,某人某地将不得不调用“模式”的构造函数,和someMethod()函数以及做T为int的实例化。但是,如果你把构造函数和someMethod()的定义放到文件Foo.cpp,当编译Foo.cpp时,编译器将看到模板代码;当编译Bar.cpp时,编译器将看到foo<int>。但任何时候决不会同时看到模板代码和foo<int>。因此,通过上面的2号规则,它根本不会产生foo <int>::someMethod()的代码

解决方法:

1.把声明跟定义写在一个文件

2,在使用的时候包含.h及cpp

例如,考虑foo.h头文件包含以下模板函数声明:

// File "foo.h"
template<typename T>
extern void foo();

现在假设文件foo.cpp实际上定义的模板函数:

// File "foo.cpp"
#include <iostream>
#include "foo.h"

template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}

假设文件main.cpp中使用这个模板函数通过调用foo<int>():

// File "main.cpp"
#include "foo.h"

int main()
{
foo<int>();
...
}

如果你编译和(试图)链接这两个.cpp文件,大多数编译器将生成链接错误。有三种的解决方案。第一个解决方案是物理上在.h文件中定义,即使它不是一个内联函数。这种解决办法可能(或可能不会!)造成重大代码膨胀,意味着可执行文件的大小可能会显显著增加(或者,如果你的编译器足够聪明,可能不会这么做)。

另一个解决办法是保留定义在.cpp文件中,只添加行template void foo<int>()到.cpp文件:

// File "foo.cpp"
#include <iostream>
#include "foo.h"

template<typename T> void foo()
{
std::cout << "Here I am!\n";
}

template void foo<int>();

如果你不能修改foo.cpp,只需创建一个新的.cpp文件,例如foo-impl.cpp如下:

// File "foo-impl.cpp"
#include "foo.cpp"

template void foo<int>();

请注意, foo-impl.cpp文件包含.cpp文件,而不是.h文件。如果你觉着这样很乱,跳个踢踏舞,想想堪萨斯,跟着我重复,“我要这么做即使它很混乱。” 你需要信任我。如果不信任或者致使好奇,前面的FAQ给出了理由。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP