Список функций C ++
-
02-07-2019 - |
Вопрос
Я работаю над довольно сложным проектом, пользовательской процедурой шифрования, если хотите (просто для развлечения), и я столкнулся с этой проблемой при разработке своего макета кода.
У меня есть ряд функций, которые я хочу иметь возможность вызывать по индексу.В частности, мне нужно иметь возможность вызывать один из них случайным образом для процесса шифрования, но затем адресовать его по определенному индексу в процессе расшифровки.
Я рассматривал классический массив функций, но моя главная проблема заключается в том, что массив функций был бы сложным в обслуживании и немного уродливым.(Цель состоит в том, чтобы поместить каждую пару функций в отдельный файл, чтобы сократить время компиляции и упростить управление кодом.) Есть ли у кого-нибудь более элегантное решение на C ++ в качестве альтернативы массиву функций?Скорость на самом деле не проблема, меня больше беспокоит ремонтопригодность.
-Николас
Решение
Вы могли бы написать что-то вроде:
class EncryptionFunction
{
public:
virtual Foo Run(Bar input) = 0;
virtual ~MyFunction() {}
};
class SomeSpecificEncryptionFunction : public EncryptionFunction
{
// override the Run function
};
// ...
std::vector<EncryptionFunction*> functions;
// ...
functions[2]->Run(data);
Вы могли бы использовать operator()
вместо того, чтобы Run
в качестве имени функции, если вы предпочитаете.
Другие советы
Что не так с массивом функций?
Вам нужно вызывать функции по индексу.Таким образом, они должны быть помещены в некую структуру, "индексируемую по индексу" каким - то образом.Массив, вероятно, является самой простой структурой, которая подходит для этой цели.
Пример (набираю из головы, может не скомпилироваться):
struct FunctionPair {
EncodeFunction encode;
DecodeFunction decode;
};
FunctionPair g_Functions[] = {
{ MyEncode1, MyDecode1 },
{ MySuperEncode, MySuperDecode },
{ MyTurboEncode, MyTurboDecode },
};
Что является "уродливым" или "трудным в обслуживании" в приведенном выше подходе?
Объект с определенным методом operator() может действовать во многом как функция, но, как правило, с ним приятнее работать.
Полиморфизм мог бы сделать свое дело:вы могли бы следовать шаблону стратегии, рассматривая каждую стратегию для реализации одной из ваших функций (или пары из них).
Затем создайте вектор стратегий и используйте его вместо списка функций.
Но, честно говоря, я не вижу проблемы с массивом функций;вы можете легко создать typedef, чтобы облегчить читаемость.Фактически, при использовании шаблона стратегии вы получите точно такую же файловую структуру.
// functiontype.h
typedef bool (*forwardfunction)( double*, double* );
// f1.h
#include "functiontype.h"
bool f1( double*, double* );
// f1.c
#include "functiontype.h"
#include "f1.h"
bool f1( double* p1, double* p2 ) { return false; }
// functioncontainer.c
#include "functiontype.h"
#include "f1.h"
#include "f2.h"
#include "f3.h"
forwardfunction my_functions[] = { f1, f2, f3 };
- Объявление функции и ее определения находятся в отдельных файлах - время компиляции в порядке.
- Группировка функций находится в отдельном файле, имеющем зависимость только от объявлений
Вы могли бы взглянуть на Повышение.Библиотека сигналов.Я полагаю, что у него есть возможность вызывать свои зарегистрированные функции, используя индекс.
Попробуйте Loki:: Класс функторов.Более подробная информация на сайте CodeProject.com
Вам нужно использовать массив указателей на функции.Единственная загвоздка заключается в том, что все функции должны иметь в основном один и тот же прототип, могут отличаться только имя функции и имена передаваемых аргументов.Возвращаемый тип и типы аргументов (а также количество аргументов и порядок) должны быть идентичны.
int Proto1( void );
int Proto2( void );
int Proto3( void );
int (*functinPointer[3])( void ) =
{
Proto1,
Proto2,
Proto3
};
Тогда вы можете сделать что-то вроде этого:
int iFuncIdx = 0;
int iRetCode = functinPointer[iFuncIdx++]();
Если бы вы заглянули в boost::signals
библиотека, вы увидите очень красивый пример, который очень элегантен:
Предположим, у вас есть 4 функции, такие как:
void print_sum(float x, float y)
{
std::cout << "The sum is " << x+y << std::endl;
}
void print_product(float x, float y)
{
std::cout << "The product is " << x*y << std::endl;
}
void print_difference(float x, float y)
{
std::cout << "The difference is " << x-y << std::endl;
}
void print_quotient(float x, float y)
{
std::cout << "The quotient is " << x/y << std::endl;
}
Затем, если вы хотите вызвать их элегантным способом, попробуйте:
boost::signal<void (float, float)> sig;
sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);
sig(5, 3);
И на выходе получается:
The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667