C++不支持类模板的声明与实现分离:
普通的实例:
\***********THead.h*********\
class TA
{
int a;
public:
TA();
}
\*********THead.cpp*********\
TA::TA()
{
}
\*********tmain.cpp********\
#include "THead.h"
#include <iostream>
using namespace std;
int main()
{
TA ta;
}
\************************\
分析:
编译main.cpp时,要调用TA的构造函数,但main.cpp没有,所以去"THead.h"找;找到THead.h时也没有找到,所以去所在的目录里找,结果找到了THead.cpp,编译了THead.cpp产生THead.obj,至此已完成了ta的构造.
过程为:
编译:main.cpp生成main.obj,THead.obj
运行连接:
首先加载main.obj,发现没有TA的构造函数模块,于是连接THead.obj找到并继续运行。
模板的实例:
\**********Test.h**********\
template<typename T>
class A
{
int a;
public:
A();
};
\*********Test.cpp********\
template<typename T>
A<T>::A()
{
}
\********main.cpp*********\
#include "Test.h"
#include <iosteram>
using namespace std;
int main()
{
A<int> a;
}
\************************\
同理分析:
编译main.cpp时,要调用A<int>的构造函数,但main.cpp没有,所以去"Test.h"找;找到Head.h时也没有
找到,所以去所在的目录里找,结果找到了Test.cpp,(注意这里只是找到,并不是调用),准备编译Test.obj,但是编译器却没有这样做,因为模板的原因,在Test.h并没有使用到A<int>(在Test.h里声明的是A<T>),因为C++规定,只有调用者要用到的时候才会去实例化,而Test.h里全只是声明语句并没有调用A<int>的声明。既然没有需要编译器也不去实例化它了。也就是,main要A<int>,Test.h就把自己的A<T>转化成A<int>但这只是声明,没有定义,这里还要注意Test.h里没有#include "Test.cpp",也就是说Test.h没有告诉Test.cpp.Test.h与Test.cpp并不存在调用的关系。可以是Test.cpp调用Test.h,而不是Test.h调用Test.cpp!!!
过程为:
编译:main.cpp生成main.obj,Test.cpp生成Test.obj
运行连接:
首先加载main.obj,发现没有A<int>的构造函数模块,于是就把这个问题交给了连接器,连接器想找到其它模块连接(Test.obj),可是没有人调用Test.cpp里的模板,也就不会实例化更不会产生关于构造函数的二进制代码。编译无奈宣告无语,显示没有构造函数。报错!
所以解决方案:
把Test.h与Test.cpp合并成一个文件,这样main找Test.h要A<int>时,Test.h就可以实例化,因为自身里有A<int>,有人要就实例化。这样的坏处就是破坏了声明与实现分工。
还有一个就在改为#include "Test.cpp",这样主函数就不用去找Test.h而直接找Test.cpp要了,有人要自然就得给实例化,这样做的坏处,一个文件可能会被包函多次,出现编译错误。
普通的实例:
\***********THead.h*********\
class TA
{
int a;
public:
TA();
}
\*********THead.cpp*********\
TA::TA()
{
}
\*********tmain.cpp********\
#include "THead.h"
#include <iostream>
using namespace std;
int main()
{
TA ta;
}
\************************\
分析:
编译main.cpp时,要调用TA的构造函数,但main.cpp没有,所以去"THead.h"找;找到THead.h时也没有找到,所以去所在的目录里找,结果找到了THead.cpp,编译了THead.cpp产生THead.obj,至此已完成了ta的构造.
过程为:
编译:main.cpp生成main.obj,THead.obj
运行连接:
首先加载main.obj,发现没有TA的构造函数模块,于是连接THead.obj找到并继续运行。
模板的实例:
\**********Test.h**********\
template<typename T>
class A
{
int a;
public:
A();
};
\*********Test.cpp********\
template<typename T>
A<T>::A()
{
}
\********main.cpp*********\
#include "Test.h"
#include <iosteram>
using namespace std;
int main()
{
A<int> a;
}
\************************\
同理分析:
编译main.cpp时,要调用A<int>的构造函数,但main.cpp没有,所以去"Test.h"找;找到Head.h时也没有
找到,所以去所在的目录里找,结果找到了Test.cpp,(注意这里只是找到,并不是调用),准备编译Test.obj,但是编译器却没有这样做,因为模板的原因,在Test.h并没有使用到A<int>(在Test.h里声明的是A<T>),因为C++规定,只有调用者要用到的时候才会去实例化,而Test.h里全只是声明语句并没有调用A<int>的声明。既然没有需要编译器也不去实例化它了。也就是,main要A<int>,Test.h就把自己的A<T>转化成A<int>但这只是声明,没有定义,这里还要注意Test.h里没有#include "Test.cpp",也就是说Test.h没有告诉Test.cpp.Test.h与Test.cpp并不存在调用的关系。可以是Test.cpp调用Test.h,而不是Test.h调用Test.cpp!!!
过程为:
编译:main.cpp生成main.obj,Test.cpp生成Test.obj
运行连接:
首先加载main.obj,发现没有A<int>的构造函数模块,于是就把这个问题交给了连接器,连接器想找到其它模块连接(Test.obj),可是没有人调用Test.cpp里的模板,也就不会实例化更不会产生关于构造函数的二进制代码。编译无奈宣告无语,显示没有构造函数。报错!
所以解决方案:
把Test.h与Test.cpp合并成一个文件,这样main找Test.h要A<int>时,Test.h就可以实例化,因为自身里有A<int>,有人要就实例化。这样的坏处就是破坏了声明与实现分工。
还有一个就在改为#include "Test.cpp",这样主函数就不用去找Test.h而直接找Test.cpp要了,有人要自然就得给实例化,这样做的坏处,一个文件可能会被包函多次,出现编译错误。
评论