C ++类模板未定义函数引用

时间:2014-03-23 18:18:10

标签: c++ c class undefined-reference template-classes

当我在我的主函数中调用模板类“add”和“greater”中的两个函数时,我一直得到未定义的引用。

所以,我有: number.h

#ifndef NUMBER_H
#define NUMBER_H

template <class T>
class number {
public:
    T x;
    T y;

    number (int a, int b){
        x=a; y=b;}
    int add (T&);
    T greater ();
};

#endif

number.cpp

#include "number.h"

template <class T>
int number<T>::add (T& rezAdd){
    rezAdd = x+y;
    return 1;
}

template <class T>
T number<T>::greater (){
        return x>y? x : y;
}

我的主文件是:resolver.cpp

#include <stdio.h>
#include <stdlib.h>
#include "number.h"

int main (int argc, char **argv) {
    int aux;
    number<int> c(3,5);

    c.add(aux);
    printf ("number added [%d]\n", c.add(aux));
    printf ("greater number: [%d]\n", c.greater());

    return 0;
}

我不断得到的错误是:

g++ -Wall -o tema1 resolver.cpp number.cpp
/tmp/ccX483J4.o: In function `main':
resolver.cpp:(.text+0x34): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x47): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x64): undefined reference to `number<int>::greater()'
collect2: ld returned 1 exit status
make: *** [all] Error 1

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:5)

你的课名错了。您的类名为cai,其中所有函数都属于名为number的类:http://ideone.com/ZayX0c

还有一件事......你不能在.cpp文件中有模板。模板函数/定义与类声明一起进入标题。这是您的未定义函数错误的原因。非模板函数放在.cpp。

#include <cstdio>
#include <cstdlib>

template <class T>
class number {
public:
    T x;
    T y;

    number (int a, int b){
        x=a; y=b;}
    int add (T&);
    T greater ();
};

template <class T>
int number<T>::add (T& rezAdd){
    rezAdd = x+y;
    return 1;
}

template <class T>
T number<T>::greater (){
        return x>y? x : y;
}


int main (int argc, char **argv) {
    int aux;
    number<int> c(3,5);

    c.add(aux);
    printf ("number added [%d]\n", c.add(aux));
    printf ("greater number: [%d]\n", c.greater());

    return 0;
}

答案 1 :(得分:4)

我更喜欢将所有函数都放在.cpp文件中,无论它们是模板函数还是常规函数。有一种方法可以通过一些基本的#ifndef魔法来做到这一点。这是你可以做的:

的main.cpp

#include "myclass.hpp"

int main()
{
  // ...
}

myclass.hpp

#ifndef MYCLASS
#define MYCLASS

template<class T>
class MyClass
{
  T val;
public:
  MyClass(T val_);
}

#define MYCLASS_FUNCTIONS
#include "myclass.cpp"

#endif

myclass.cpp

#ifndef MYCLASS_FUNCTIONS
#include "myclass.hpp"

// regular functions:
// ...

#else

// template functions:
template<class T>
MyClass<T>::MyClass(T val_)
    :val(val_)
{}

// ...
#endif

这是预编译器如何看待它。我们有两个.cpp个文件。

  1. 当我们编译main.cpp时,我们:
    1. 包括myclass.hpp
    2. 检查MYCLASS是否未定义,并且
    3. 定义
    4. 为编译器提供生成的类的定义(来自模板类)
    5. 包括myclass.cpp
    6. 定义MYCLASS_FUNCTIONS
    7. 检查是否定义了MYCLASS_FUNCTIONS,它是
    8. 为编译器提供生成函数的定义(来自模板函数)
  2. 当我们编译myclass.cpp时
    1. 检查是否定义了MYCLASS_FUNCTIONS,它不是
    2. 包括myclass.hpp
    3. 检查MYCLASS是否未定义,并且
    4. 定义
    5. 给编译器定义类
    6. 包括myclass.cpp
    7. 再次加入myclass.hpp
    8. 此时MYCLASS已定义,因此请勿在内部执行任何操作,请返回myclass.cpp
    9. 检查是否定义了MYCLASS_FUNCTIONS,它是
    10. 给编译器生成函数的定义(来自模板函数)
    11. 退出包含两次
    12. 将所有常规函数传递给编译器

答案 2 :(得分:3)

addgreater功能模板的定义移至number.h

请注意,addgreater不是功能,他们是功能模板。要创建实际的函数,编译器必须为特定类型(例如int)实例化模板,并且只有在它发现模板的定义时才能访问模板的定义。实例是必需的。

编译number.cpp时,编译器可以访问模板&#39;定义,但它没有看到任何需要特定实例的代码(例如number<int>),因此它不会生成实例。

编译resolver.cpp时,编译器发现需要为int类型实例化这些模板,但由于它没有定义,所以它不能。因此它生成&#34;外部引用&#34;,基本上注意告诉链接器在其他目标文件中查找这些函数。

结果是函数模板没有在 目标文件中实例化 - 在一个中因为编译器不知道它应该,而在另一个因为它不能 - 所以当链接器寻找它们(解析那些外部引用)时,它无法找到它们。这就是你收到错误的原因。

将模板函数定义移动到标题中会使编译器在编译main.cpp时可见,因此它能够为int类型实例化这些函数。由于这个原因,函数模板通常需要在头文件中定义,而不是.cpp个文件。