Время размышления. Почему вы все равно хотите разделить файл?
Как видно из названия, конечная проблема, которую я имею, - это множественные ошибки компоновщика определения. Я действительно исправил проблему, но я не исправил проблему правильно. Перед началом работы я хочу обсудить причины разделения файла класса на несколько файлов. Я попытался использовать все возможные сценарии здесь - если я пропустил, пожалуйста, напомните мне, и я могу внести изменения. Надеемся, что правильнее:
Причина 1 Чтобы сэкономить место:
У вас есть файл, содержащий объявление класса со всеми членами класса. Вы помещаете #include защитников вокруг этого файла (или #pragma один раз), чтобы избежать конфликтов, если вы # включаете файл в два разных файла заголовка, которые затем включаются в исходный файл. Вы компилируете отдельный исходный файл с реализацией любых методов, объявленных в этом классе, поскольку он загружает много строк кода из вашего исходного файла, который немного очищает вещи и вводит некоторый порядок в вашу программу.
Пример. Как вы можете видеть, приведенный ниже пример можно улучшить, разделив реализацию методов класса на другой файл. (Файл .cpp)
// my_class.hpp
#pragma once
class my_class
{
public:
void my_function()
{
// LOTS OF CODE
// CONFUSING TO DEBUG
// LOTS OF CODE
// DISORGANIZED AND DISTRACTING
// LOTS OF CODE
// LOOKS HORRIBLE
// LOTS OF CODE
// VERY MESSY
// LOTS OF CODE
}
// MANY OTHER METHODS
// MEANS VERY LARGE FILE WITH LOTS OF LINES OF CODE
}
Причина 2 Чтобы предотвратить множественные ошибки компоновщика определений:
Возможно, это основная причина, по которой вы разделили бы реализацию от объявления. В приведенном выше примере вы можете переместить тело метода вне класса. Это сделало бы его более чистым и структурированным. Однако в соответствии с этим question приведенный выше пример имеет неявные спецификаторы inline
. Перемещение реализации из класса в класс вне класса, как в приведенном ниже примере, вызовет ошибки компоновщика, поэтому вы должны либо вставить все, либо переместить определения функций в файл .cpp.
Пример: _ Пример ниже приведет к "ошибкам компоновщика нескольких определений", если вы не переместите определение функции в файл .cpp или не укажете функцию как встроенную.
// my_class.hpp
void my_class::my_function()
{
// ERROR! MULTIPLE DEFINITION OF my_class::my_function
// This error only occurs if you #include the file containing this code
// in two or more separate source (compiled, .cpp) files.
}
Чтобы устранить проблему:
//my_class.cpp
void my_class::my_function()
{
// Now in a .cpp file, so no multiple definition error
}
Или:
// my_class.hpp
inline void my_class::my_function()
{
// Specified function as inline, so okay - note: back in header file!
// The very first example has an implicit `inline` specifier
}
Причина 3 Вы хотите снова сохранить место, но на этот раз вы работаете с классом шаблона:
Если мы работаем с классами шаблонов, мы не можем переместить реализацию в исходный файл (файл .cpp). То, что в настоящее время не разрешено (я предполагаю) либо стандартным, ни текущим компилятором. В отличие от первого примера Reason 2, мы можем поместить реализацию в файл заголовка. Согласно этому question, причина в том, что методы класса шаблонов также подразумевали спецификаторы inline
. Это верно? (Кажется, это имеет смысл.) Но никто, похоже, не знал вопроса, на который я только что ссылался!
Итак, два примера ниже идентичны?
// some_header_file.hpp
#pragma once
// template class declaration goes here
class some_class
{
// Some code
};
// Example 1: NO INLINE SPECIFIER
template<typename T>
void some_class::class_method()
{
// Some code
}
// Example 2: INLINE specifier used
template<typename T>
inline void some_class::class_method()
{
// Some code
}
Если у вас есть заголовочный файл класса шаблона, который становится огромным из-за всех функций, которые у вас есть, то я считаю, что вам разрешено переместить определения функций в другой файл заголовка (обычно это .tpp файл?), а затем #include file.tpp
в конце вашего файла заголовка, содержащего объявление класса. Вы не должны включать этот файл нигде, но, следовательно, .tpp
, а не .hpp
.
Я предполагаю, что вы также можете сделать это с помощью встроенных методов обычного класса? Это разрешено также?
Время запроса
Итак, я сделал несколько утверждений, большинство из которых относятся к структурированию исходных файлов. Я думаю, что все, что я сказал, было правильным, потому что я сделал некоторые фундаментальные исследования и "узнал некоторые вещи", но это вопрос, и поэтому я не знаю точно.
Что это сводится к тому, как организовать код внутри файлов. Я думаю, что я выяснил структуру, которая всегда будет работать.
Вот что я придумал. (Это, например, "Стандарт организации/структуры файла кода класса Ed Bird". Не знаю, будет ли он еще очень полезен, это вопрос о спросе.)
- 1: Объявить класс (шаблон или другое) в файле
.hpp
, включая все методы, функции друзей и данные. - 2: В нижней части файла
.hpp
,#include
a.tpp
файл, содержащий реализацию любых методовinline
. Создайте файл.tpp
и убедитесь, что все методы указаны какinline
. - 3Все остальные члены (не встроенные функции, функции друзей и статические данные) должны быть определены в файле
.cpp
, который#include
файл.hpp
вверху, чтобы предотвратить ошибки, такие как "класс ABC не был объявлен". Поскольку все в этом файле будет иметь внешнюю связь, программа будет правильно связываться.
Существуют ли такие стандарты в промышленности? Будет ли стандарт я придумал работу во всех случаях?