Вопрос

Я работаю над довольно сложным проектом, пользовательской процедурой шифрования, если хотите (просто для развлечения), и я столкнулся с этой проблемой при разработке своего макета кода.

У меня есть ряд функций, которые я хочу иметь возможность вызывать по индексу.В частности, мне нужно иметь возможность вызывать один из них случайным образом для процесса шифрования, но затем адресовать его по определенному индексу в процессе расшифровки.

Я рассматривал классический массив функций, но моя главная проблема заключается в том, что массив функций был бы сложным в обслуживании и немного уродливым.(Цель состоит в том, чтобы поместить каждую пару функций в отдельный файл, чтобы сократить время компиляции и упростить управление кодом.) Есть ли у кого-нибудь более элегантное решение на 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top