ArrayList.h
#pragma once
template <class T>
class ArrayList
{
public:
ArrayList(int size);
~ArrayList(void);
private:
T* arrayList;
int maxSize;
};
ArrayList.cpp
#include "ArrayList.h"
template <class T>
ArrayList<T>::ArrayList(const int size)
{
maxSize = size;
arrayList = new T[maxSize];
}
template <class T>
ArrayList<T>::~ArrayList(void)
{
delete [] arrayList;
}
源.cpp
#include <iostream>
#include "ArrayList.h"
using namespace std;
int main()
{
ArrayList<int> list(2);
system("pause");
return 0;
}
出现的错误是
将三个文件写到一个文件里后就没有错误了
#include <iostream>
using namespace std;
template <class T>
class ArrayList
{
public:
ArrayList(int size);
~ArrayList(void);
private:
T* arrayList;
int maxSize;
};
template <class T>
ArrayList<T>::ArrayList(int size)
{
maxSize = size;
arrayList = new T[maxSize];
}
template <class T>
ArrayList<T>::~ArrayList(void)
{
delete [] arrayList;
}
int main()
{
ArrayList<int> list(2);
system("pause");
return 0;
}
请问这是为什么
怪我咯2017-04-17 13:06:54
The simple answer is "the template should be written in a .h file".
But I think this is not what the subject wants.
To understand this problem, you must first understand the meaning of separating .h and .cpp.
Usually we separate .cpp and .h not for modularity.
Modularity itself embodies "putting different things in different files", but .cpp and .h are "putting the same things in two files respectively".
In fact, you can not write the .h file at all, just write .cpp, and then #include "bla.cpp", it will still compile.
(As long as the names of functions/variables/classes, etc. in .cpp do not crash...)
The biggest reason to separate .h and .cpp is to compile each .cpp separately.
When building the program, we compile all .cpp (source code files) into .o (object files), and then integrate .o into executable files (or libraries).
Suppose there are 100 .cpp files in our software project, and we only changed one of them after the last build.
The best case scenario is that only one .o file needs to be recompiled, and the remaining 99 can be directly used to integrate the executable file, saving compilation time.
This is very useful for building large-scale software. You can't just change a line of Office code and recompile dozens of GB of source code...
Then we have another question:
.cpp are all separated, and they don’t know each other’s existence. So what should we do if a.cpp wants to use things in b.cpp?
a.cpp needs to know what functions b.cpp provides, but it does not need to know how those functions are implemented.
And "showing the provided functions" is the role of the .h file: I provide a class named BlaBlaBla, which contains such-and-such variables and such-and-such methods, and a function called doSomething, which accepts two ints as Parameters,...
So all .cpp only needs to import .h and see what can be done.
They don’t need to worry about how the functions mentioned in .h are implemented. Anyway, as long as they know that they will be eventually integrated into an executable file, it is enough.
This achieves dependency separation, allowing each .cpp to be compiled separately.
But templates are different: templates cannot be compiled separately.
Why? Take a look at the following examples:
template <typename T>
T* makeArray(size_t n) {
return new T[n];
}
The compiler sees this line of code, what should it do?
Typically, if the compiler sees something like:
SomeClass* makeArray(size_t n) {
return new SomeClass[n];
}
It should write binary code like this in .o:
分配一段足够长的空间(n * sizeof(SomeClass))
找到SomeClass对应的构造函数
对空间里的每一个sizeof(SomeClass)大小的位置,执行一遍SomeClass的构造函数
返回空间的地址
But in the case of templates, it can't do it: it doesn't know what T is at all, sizeof(T) is unknown, and it can't be compiled!
Another problem is that templates have some characteristics that prevent you from knowing what the compiled code looks like until you actually know T.
One of them is called partial specialization:
template<typename T>
int getValue(T t) {
return t.value;
}
template<>
int getValue(int t) {
return 0;
}
How to compile this thing? Without knowing what T is, you don’t know whether to use the upper version or the lower version...
Therefore, template code cannot be compiled into .o files.
To use this template in other .cpp, you can only copy and paste it directly into your own code, which is what #include does.
In fact, this is also the experience of the name "template": I am just a template of the source code. It is used for you to copy and paste and then modify it, not for compilation!
伊谢尔伦2017-04-17 13:06:54
That error is because the template cannot be instantiated. The declaration of the class template and the definition of its member functions should be placed in the same file, that is, in the .h file.
黄舟2017-04-17 13:06:54
Let me tell you the final answer.
In fact, someone has already proposed the things in cpp for this template. There is one of the most awesome companies in the world called EDG, which is responsible for writing the correct C++ compiler, and then telling the standards committee what they think, and by the way, selling their C++/Java/Fortran compiler front-end. It took them two years to finally do this, which included super complicated work such as how to serialize the AST of the template code into obj/lib so that it can be recompiled during linking. Finally came to a conclusion:
Only we know how to do such an awesome function, you can’t do it.
So the whole world gave up and never mentioned this matter again.
So other answers say a lot of things that are actually incorrect, because there is no reason to prevent the C++ compiler from compiling the source code of the template when linking. These are all engineering trade-offs. There are almost no benefits to doing this, but the complexity of the compiler has increased a lot. So it doesn't make much sense.
伊谢尔伦2017-04-17 13:06:54
If you don’t use it#pragma once
, try this instead
#ifndef ARRAY_LIST_H
#define ARRAY_LIST_H
#endif
大家讲道理2017-04-17 13:06:54
When instantiating template classes and functions, you need to "see" the relevant implementations. Otherwise, how can the compiler specialize this part of the code?