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