Причина вашей проблемы заключается в организации файлов в C ++.
О заголовках и источниках
Источники - это файлы, которые скомпилированы в двоичные «объектные файлы», а затем соединены вместе для создания окончательного двоичного файла (либо библиотеки, либо исполняемого файла).
Но чтобы один источник использовал код, определенный в другом источнике, они должны совместно использовать «объявления» кода. Таким образом, объявление должно быть размещено в общих файлах, которые мы будем называть заголовочными файлами.
Обычно код в заголовках не является «истинным кодом», а только декларацией о существовании этого истинного кода.
Это то, что вы сделали со своим пользовательским вектором: поместите объявление в заголовок, а реализацию в исходный, и включите заголовок в основной.
О вкладывании
Теперь некоторый «истинный код» может быть помещен в заголовки, обычно путем добавления к нему ключевого слова «inline».
Опять же, это не совсем верный код: компилятор и компоновщик выяснят, что с ним делать, но он может либо:
- Переместить код функции в «объектный файл» и связать там все остальные «объектные файлы»
- Встроенный код, в котором используется встроенная функция
- Два вышеуказанных решения одновременно
Но встроенная функция вполне может исчезнуть из двоичного файла, если она не используется.
О шаблонах
Шаблоны чем-то похожи на объявление: это не "истинный код", а "потенциальный код". Это даже более «потенциал», чем встроенный код, потому что код шаблона должен быть создан для правильных параметров шаблона.
Как и для любого другого кода, для использования кода шаблона ваш исходный файл должен иметь доступ к объявлению. Но в этом случае объявление шаблона является одновременно и "потенциальным объявлением", и "потенциальной реализацией" , который будет создан компилятором для правильных типов, которые вы используете.
Существуют и другие способы работы с шаблонами, но так будет всегда.
Последний совет
При работе с шаблонами (или встроенным кодом) может быть очень очень удобно разбивать заголовок на несколько файлов (например, при работе с циркулярными зависимостями декларации).
* * Пример 1 042:
файл: MyObject.hpp
#include <MyObject_header.hpp>
#include <MyObject_source.hpp>
файл: MyObject_header.hpp
class MyObject
{
// Etc.
} ;
файл: MyObject_source.hpp
#include <MyObject_header.hpp>
MyObject::MyObject()
{
// etc.
}
// etc.