C++模板类多文件编译 无定义 解决办法

0x01 实现模板类

通常在C/C++中实现一个类,都是将声明放在.h文件中,将定义(实现)放在.c或者.cpp文件中,例如:

通常示例多文件编译

myClass.h

1
2
3
4
5
6
7
8
9
10
#ifndef MY_CLASS_H
#define MY_CLASS_H
class myClass {
public:
myClass();
...
private:
...
}
#endif

myClass.cpp

1
2
3
4
5
6
#include "myClass.h"

myClass::myClass() {
...
}
...

myClass.main.cpp

1
2
3
4
5
6
7
#include "myClass.h"
int main()
{
myClass mClass();
...
return 0;
}

然后编译的时候直接运行makefile或者执行命令:

1
2
3
4
g++ -c myClass.cpp
g++ -c myClass.main.cpp
g++ myClass.o myClass.main.o -o main
./main

就可以运行了。这在没有设计模板类的时候一切都会很顺利,但是只要涉及到了模板类就…

模板类多文件遇到的问题

就拿一个循环队列来举例子吧。

cycleQueue.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef CYCLE_QUEUE_HPP
#define CYCLE_QUEUE_HPP

#include <exception>

template<class T>
class cycleQueue
{
private:
unsigned int size;
unsigned int front;
unsigned int tail;
T* data;
public:
cycleQueue(unsigned int nsize);
...
int length();
};

#endif

cycleQueue.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "cycleQueue.hpp"

template<class T>
cycleQueue<T>::cycleQueue(unsigned int nsize)
:size(nsize + 1),
front(0),
tail(0)
{
...

template<class T>
int cycleQueue<T>::length()
{
int len = (int)tail - (int)front;
return len >= 0 ? len : -len;
}

cycleQueue.main.cpp

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;

#include "cycleQueue.hpp"

int main()
{
cycleQueue<int> queue(5);
...
return 0;
}

按照常理,正常使用g++编译即可生成main可执行文件,但是在执行最后一步链接的时候会出现问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ g++ -c cycleQueue.cpp
$ g++ -c cycleQueue.main.cpp
$ g++ cycleQueue.o cycleQueue.main.o -o main
Undefined symbols for architecture x86_64:
"cycleQueue<int>::isFull()", referenced from:
_main in cycleQueue.main.o
"cycleQueue<int>::length()", referenced from:
_main in cycleQueue.main.o
"cycleQueue<int>::deQueue()", referenced from:
_main in cycleQueue.main.o
"cycleQueue<int>::enQueue(int)", referenced from:
_main in cycleQueue.main.o
"cycleQueue<int>::isEmpty()", referenced from:
_main in cycleQueue.main.o
"cycleQueue<int>::cycleQueue(unsigned int)", referenced from:
_main in cycleQueue.main.o
"cycleQueue<int>::~cycleQueue()", referenced from:
_main in cycleQueue.main.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

可以看到,单独编译实现代码的时候是可以通过的,但是在两个文件链接起来的时候出现了问题。经过查找资料,貌似是因为实现文件中实现的是cycleQueue<T>这个类型,但是main中使用了cycleQueue<int>这个类型,所以编译器找不到这个类型的定义。

想了想,这好办啊,只要把实现的定义也加进去就好了呀。

于是乎,cycleQueue.hpp就成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef CYCLE_QUEUE_HPP
#define CYCLE_QUEUE_HPP

#include <exception>

template<class T>
class cycleQueue
{
...
};

#include "cycleQueue.cpp"

#endif

而为了解决include重复问题,cycleQueue.cpp也变成了:

1
2
3
4
5
6
7
8
#ifndef CYCLE_QUEUE_CPP
#define CYCLE_QUEUE_CPP

#include "cycleQueue.hpp"

...

#endif

于是乎,搭配makefile就可以快速实现编译了

1
2
3
4
5
6
7
8
9
10
11
12
cycleQueue: cycleQueue.o cycleQueue.main.o
g++ cycleQueue.o cycleQueue.main.o -o cycleQueue
make clean

cycleQueue.o: cycleQueue.cpp
g++ -c cycleQueue.cpp

cycleQueue.main.o: cycleQueue.main.cpp
g++ -c cycleQueue.main.cpp

clean:
rm *.o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ ls -la
total 32
drwxr-xr-x 6 chenke staff 192 Sep 7 13:50 .
drwxr-xr-x 3 chenke staff 96 Sep 7 14:10 ..
-rw-r--r-- 1 chenke staff 956 Sep 7 13:40 cycleQueue.cpp
-rw-r--r-- 1 chenke staff 403 Sep 7 13:32 cycleQueue.hpp
-rw-r--r-- 1 chenke staff 695 Sep 7 13:43 cycleQueue.main.cpp
-rw-r--r-- 1 chenke staff 242 Sep 7 13:01 makefile

$ make
g++ -c cycleQueue.cpp
g++ -c cycleQueue.main.cpp
g++ cycleQueue.o cycleQueue.main.o -o cycleQueue
make clean
rm *.o

$ ls -la
total 80
drwxr-xr-x 7 chenke staff 224 Sep 7 14:12 .
drwxr-xr-x 3 chenke staff 96 Sep 7 14:10 ..
-rwxr-xr-x 1 chenke staff 20512 Sep 7 14:12 cycleQueue
-rw-r--r-- 1 chenke staff 956 Sep 7 13:40 cycleQueue.cpp
-rw-r--r-- 1 chenke staff 403 Sep 7 13:32 cycleQueue.hpp
-rw-r--r-- 1 chenke staff 695 Sep 7 13:43 cycleQueue.main.cpp
-rw-r--r-- 1 chenke staff 242 Sep 7 13:01 makefile

一顿操作猛如虎23333

Author: SmallXeon
Link: https://hexo.chensmallx.top/2019/09/07/C-template-multi-files-compile/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
一些推广链接
几个便宜量大的小✈场: FASTLINK, YToo, 论坛邀请注册: ,
便宜量大但是稳定性不足的VPS: Virmach, 价格略贵但好用的VPN: , ,