不生成模板中的虚拟方法

时间:2012-11-28 19:46:16

标签: c++ templates inheritance virtual-method

  

可能重复:
  Why do I get “unresolved external symbol” errors when using templates?

我有一套复杂的课程 具有子参数化类A的类_A,其具有两个子节点A1和A2 类B.包含类_A的对象上的指针作为成员。有两个子类B1和B2,分别对应A1和A2类。 B1构造_A作为A1。 B2分别为A2 最后在类B中定义了子BY的类Y 现在它是如何出现在文件中的。

tf1.h

#include <iostream>

struct Y{ // goes to the file tf2.h as ancestor of the class B::BY
};


struct _A{ // goes to the file tf2.h as a member of the class B
};

template<class X>
struct A: public _A {  // goes to two classes below only as an ancestor
    virtual void method();
    protected:
    virtual void m() = 0;
};

template<class X>
struct A1: public A<X>{  // goes to the file tf2.h to the class B1
    protected:
    void m();
};

template<class X>
struct A2: public A<X>{  // goes to the file tf2.h to the class B2
    protected:
    void m();
};

tf1.cpp

#include "tf1.h"


template<class X>
void A<X>::method(){
    /* here the class X used */
    std::cout << "A::method called" << std::endl;
    m();
}

template<class X>
void A1<X>::m(){
    std::cout << "A1::m called" << std::endl;
}

template<class X>
void A2<X>::m(){
    std::cout << "A1::m called" << std::endl;
}

tf2.h

#include "tf1.h"

class B{   // is the counterpain of the class _A
    protected:
    class BY: public Y{
    };

    _A * mp_x;
};


class B1: public B{  // is the counterpain of the class A1
    public:
    B1(){mp_x = new A1<BY>; std::cout << "B::B is called" << std::endl;}
};

class B2: public B{  // is the counterpain of the class A2
    public:
    B2(){mp_x = new A2<BY>; std::cout << "C::C is called" << std::endl;}
};

tfmain.cpp

#include <stdlib.h>

#include "tf2.h"

int main (int,char**){
    B2 b2;
    system ("PAUSE");
}

最后,这个问题。

d:>g++ -std=c++0x tfmain.cpp -o tfmain.exe
ccB2BnSP.o:tfmain.cpp:(.rdata$_ZTV2A2IN1B2BYEE[__ZTV2A2IN1B2BYEE]+0x8): undefined reference to `A<B::BY>::method()'
ccB2BnSP.o:tfmain.cpp:(.rdata$_ZTV2A2IN1B2BYEE[__ZTV2A2IN1B2BYEE]+0xc): undefined reference to `A2<B::BY>::m()'
ccB2BnSP.o:tfmain.cpp:(.rdata$_ZTV1AIN1B2BYEE[__ZTV1AIN1B2BYEE]+0x8): undefined reference to `A<B::BY>::method()

我正在使用MinGW v4.7.2

3 个答案:

答案 0 :(得分:3)

您不能将模板化函数定义放在.cpp文件中,您必须将它们放在头文件中。这是模板的奇怪限制。

它与您的函数的模板化版本仅在使用时生成的事实有关。因此,您无法预编译模板化函数,因为它尚未使用,因此它不会生成所有内容。

答案 1 :(得分:3)

简单来说,你不能把模板定义放到cpp文件中(有变通方法......但不是很愉快)

原因是编译器只在您调用该模板的第一个点实例化一个模板,因为编译器需要知道用什么类型来实例化模板。

现在,如果您将模板定义放入单独的cpp文件中,该文件将单独编译到其自己的翻译单元中。编译器在哪里查找实例化模板的情况?

例如

// Template.h
template <typename T>
class templateObj { ~templateObj(); };

// Template.cpp
#include "Template.h"
template <typename T>
templateObj::~templateObj() { /* delete stuff! */ }

// YourFile.cpp
#include "Template.h"
templateObj<int> myObj;

现在,当编译器编译此代码时。 它将生成两个翻译单元,一个用于Template.cpp,另一个用于YourFile.cpp

请注意,Template.cpp没有一个关于YourFile.cpp是什么以及内部含义的线索。因此,无法在YourFile.cpp中了解您使用templateObj模板参数类型int。因此,在Template.cpp的结果转换单元中,编译器将生成templateObj的析构函数的实例化版本

现在,让我们看看YourFile.cpp,当编译器发现您正在使用类型templateObj实例化int时,它会查找templateObj的定义。由于您已包含Template.h,因此编译器会发现您已为templateObj声明了析构函数。但定义在哪里?

编译器没有看到~templateObj()的定义,也不知道此时要查找的位置。 因此它只是暂缓,并将传递给链接器以搜索要链接的正确模块。

现在问题在于:

在编译器刚刚生成的两个翻译单元中,YourFile.oTemplate.o都没有template<int>::~template()的定义。 链接器读入YourFile.o并期望将templateObj的析构函数版本链接到,但唯一的其他翻译单元Template.o没有它;事实上,它有没有

那么现在呢?链接器必须抱怨...这就是你得到的错误信息。


关于代码发生的更多细节:

  • 制作了两个翻译单元:tf1.otfmain.o
  • tf1.o是根据tf1.cpp及其包含的内容生成的。
  • tfmain.o是根据tfmain.cpp生成的,无论其包含的内容。

那么他们包括什么? tf1.cpptfmain.cpp了解其余代码的内容是什么?

tf1.cpp

  • #include "tf1.h" ==&gt; #include <iostream> ...

tfmain.cpp

  • #include "tf2.h" ==&gt;其中#include "tf1.h" ==&gt; #include <iostream> ...

tf1.cpp有什么作用?它知道什么?

  • 了解Y_A
  • 声明
  • 知道AA1A2
  • 模板声明
  • 模板定义适用于AA1A2
  • 中的各种方法

tfmain.cpp有什么作用?它知道什么?

  • 了解BB1B2Y_A <的 声明 / LI>
  • 知道AA1A2
  • 模板声明
  • BB1B2
  • 中的各种方法 定义
  • mainB2
  • 的实例

所以,现在的问题是:

tf1.cpptf2.htfmain.cpp有何了解?是否知道您正在为B2创建一个实例A2,其类型为BY

tfmain.cpp是否了解tf1.cpp的任何内容?它是否知道AA1A2 ??

中方法的定义

他们 NOT 互相认识,因此编译器无法为翻译单元tf1.o中的模板类生成定义代码(此时,它甚至不知道你正在为B2创建一个实例A2类型BY)的实例。

最后,链接器无法找到tfmain.o要求的代码,因为它是 NOT

答案 2 :(得分:0)

Xymostech回答了你的问题,但我不同意这种限制很奇怪。 ;)This should clarify this matter for you.