模板类继承链接器错误

时间:2013-11-05 12:59:22

标签: c++ templates inheritance c++11 linker-errors

假设我有一个类模板A,而非模板类B继承自A。虽然A编译正常,但编译B会触发链接器错误。具体地,

A.hpp

#ifndef A_HPP_INCLUDED
#define A_HPP_INCLUDED

template <typename T>
class A { 
public:
    A();
    A(A<T>&& );
    virtual ~A();

    /* ... */
protected:
    T x;
};
#include A.tpp
#endif

A.tpp

#include "A.hpp"

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

template <typename T>
A<T>::A(A<T>&& other)
   : x(std::move(other.x)) { }

template <typename T>
A<T>::~A() { ... }

testA.cpp

#include "A.hpp"

int main() {

    A<std::string> a;

    /* ... */

    return 0;
}

按如下方式编译testA.cpp成功:

$ g++ -std=c++11 testA.cpp&lt; - 确定

接下来是继承自class B的非模板A

B.hpp

#ifndef B_HPP_INCLUDED
#define B_HPP_INCLUDED
#include "A.hpp"
class B
    : public A<std::string> {
public:
    B();
    virtual ~B();

    static A<std::string> foo();
};
#endif

B.cpp

#include "B.hpp"

B::B()
    : A(std::move(foo())) { }

B::~B() { }

A<std::string> B::foo() { ... }

testB.cpp

#include "B.hpp"

int main() {
    B b;

    /* ... */

    return 0;
}

testB.cpp的编译似乎没问题,但链接器不是一个快乐的露营者:

尝试1

$ g++ -std=c++11 testB.cpp   
Undefined references to B(), and ~B()
collect2: error: ld returned 1 exit status

尝试2

$ g++ -std=c++11 testB.cpp B.cpp
Undefined reference to B.foo()
collect2: error: ld returned 1 exit status

非常感谢任何帮助/想法。 ld先生大部分时间都让我活了起来,并威胁着我的理智。

修改

谢谢Mike Seymour!这个最小的例子不是真实代码的真实再现,因为在实现中确实缺少一个限定符,并且是装备中的扳手。

3 个答案:

答案 0 :(得分:3)

我建议你在两个不同的传递中编译和链接:

g++ -c -std=c++11 -o B.o B.cpp
g++ -c -std=c++11 -o TestB.o TestB.cpp
g++ -o test.exe B.o TestB.o

如果我的建议打破了它至少会清楚哪里缺少什么,你将能够使用nm调试单个目标文件。

答案 1 :(得分:1)

  $ g++ -std=c++11 testB.cpp   
  Undefined references to B(), and ~B()

这个显然是错的(我只是说,因为我不明白你为什么要这样做)。 您只编译一个翻译单元,它使用另一个(B.cpp)中未编译的符号定义。

我认为您应该在 testB.cpp 中的...后面发布实际内容,以帮助找到问题。它可能是您使用foo()

预期:由于foo是您的类的静态成员方法,因此您在测试中的调用应如下所示:

B::foo();

答案 2 :(得分:1)

在您的真实代码中,ParsedData::parsedStream是一个模板,因此应该在标头中定义,以便它可以在每个可能需要实例化它的翻译单元中使用。

此外,即使在.cpp文件中也没有定义它,因为您不使用ParsedData::限定符,而是在命名空间范围内声明了不同的模板。