У меня проблемы с поиском решений для повторного использования общих пользовательских функций, таких как isPrime, isEven и т. Д. Я знаю, что буду использовать их снова и снова, но я хочу избегать записи их снова и снова в каждом файле .cpp. Я рассмотрел использование файла заголовка для хранения всех этих функций, но я также услышал комментарий о том, что функция будет скомпилирована вместе с другими функциями в заголовке. Таким образом, по мере увеличения числа пользовательских функций время компиляции увеличивается.
Кроме того, я хочу избежать добавления множества отдельных файлов, таких как isPrime.cpp, isEven.cpp и т. Д.
Как мне эффективно использовать эти функции? Пожалуйста, покажите простой шаблон для организации каждого файла.
Благодарю.
Есть около четырех вещей, которые являются «очевидными» решениями. Там могут быть другие.
В порядке «сложности»:
Добавьте все функции как встроенные функции в заголовок. Это хорошо, если функции действительно крошечные, но как только они станут достаточно большими, это не будет хорошим решением (поскольку функции могут многократно копироваться в один и тот же исполняемый файл).
Создайте один файл «functions.cpp», который содержит набор функций (подходящим образом выбранных для совместного использования), и объявите их в «functions.h» — теперь вам просто нужно связать еще один файл. Недостатком является то, что ВСЕ функции из «functions.cpp» включены в ваш окончательный исполняемый файл, независимо от того, используются ли они на самом деле или нет (если компилятор не очень умен и может «убить» мертвые функции — большинство компиляторов этого не делают сделай это).
Сделай библиотеку. В этом случае вам нужен один исходный файл для каждой функции, который скомпилирован и встроен в один библиотечный файл functions.a или functions.lib. Опять же, вам нужен заголовочный файл (или несколько), чтобы объявить ваши функции, а затем связать с библиотекой, чтобы включить функции в ваш исполняемый файл. Когда компоновщик создает ваш конечный исполняемый файл, каждая функция, которая «нужна» вашему исполняемому файлу, берется из библиотеки, но другие функции, которые вам «не нужны», не будут частью исполняемого файла.
Сделать общую библиотеку. Это похоже на создание библиотеки, за исключением того, что вместо включения кода для функций в исполняемый файл при создании функций будет создан отдельный «исполняемый» файл общей библиотеки (.dll, .dynlib или .so). Когда вы используете разделяемую библиотеку, вам все равно нужно передать «библиотеку» команде компоновщика, но исполняемый файл будет иметь только «заглушку» (или «thunk»), которая знает, как вызывать код разделяемой библиотеки. Это действительно полезно, когда у вас есть что-то вроде cout
или же printf
что почти каждая программа на C ++ использует, и на машине есть сотни или тысячи программ, потому что все эти программы используют то же самое printf
или же cout
код, а не иметь копию каждого.
И если вы думаете, что добавление 2-3 файлов в командную строку — это большая работа, я бы посоветовал вам не использовать LLVM. Это библиотеки, которые я добавляю для сборки своего компилятора (к счастью, есть инструмент, который автоматически делает это):
-lLLVMLTO -lLLVMObjCARCOpts -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMIRReader -lLLVMAsmParser -lLLVMTableGen -lLLVMDebugInfo -lLLVMOption -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMJIT -lLLVMLineEditor -lLLVMMCDisassembler -lLLVMInstrumentation — lLLVMInterpreter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMProfileData -lLLVMTarget -lLLVLllMLVMlMMVMlMVMlMMMMMMMMMMMMMMMMMMMMMBMMMMMMMBMMMMMMMMB
Вы можете иметь только заголовок файл, который содержит определение и объявления функции (скажем, например, functions.hpp
), и включайте его всякий раз, когда вы используете функции (с #include "functions.hpp"
):
// functions.hpp
void func() { … }
// main.cpp
#include "functions.hpp"int main() {
func();
}
В противном случае вы можете иметь файл заголовка (опять же, например, functions.hpp
), в котором вы определяете сигнатуры функций, и один файл, в котором их можно определить (например, function.cpp
).
// functions.hpp
void func();
// functions.cpp
#include "functions.hpp"void func() { … }
// main.cpp
#include "functions.hpp"int main() {
func();
}
В последнем вам придется скомпилировать functions.cpp
и связать объектный файл с main.cpp
,
Обычный способ сделать это — объявить методы в заголовочном файле, а затем определить их в другом. Например, в common.hpp
Вы могли бы поставить:
bool isPrime(int number);
bool isEven(int number);
А потом внутри common.cpp
Вы могли бы поставить:
bool isPrime(int number) { ... }
bool isEven(int number) { ... }
А потом ты #include "common.hpp"
чтобы получить доступ к этим функциям. Обратите внимание, что вы можете столкнуться с проблемами с несколькими объявлениями одного и того же метода, если вы не используете включить охрану.
также неплохо объявить «#pragma Once» в заголовочном файле. таким образом, если ваши заголовочные файлы были включены в другой заголовочный файл, а третий файл включает в себя как второй, так и первый заголовочный файл, вы избежите множественных включений. Если вы не используете Visual Studio, запишите содержимое файла заголовка между блоками #ifndef:
#ifndef HEADER_FILE
#define HEADER_FILE
//your header file contents go here
#endif
// ------------------------
// utilities.h
bool isPrime( int );
bool isEven( int );
// ------------------------
// utilities.cpp
#include utilities.h
bool isPrime( int a ){ ... }
bool isEvent( int a ){ ... }
// ------------------------
// other.cpp
#include utilities.h
int main()
{
isPrime( 2 );
return 0;
}