Pregunta

Estoy trabajando en un proyecto bastante complejo, una rutina de cifrado personalizada por así decirlo (solo por diversión) y me encontré con este problema al diseñar el diseño de mi código.

Tengo una serie de funciones a las que quiero poder llamar por índice.Específicamente, necesito poder llamar a uno aleatoriamente para el proceso de cifrado, pero luego abordarlo mediante un índice específico en el proceso de descifrado.

Estaba considerando una matriz de funciones clásica, pero mi principal preocupación es que una matriz de funciones sería difícil de mantener y un poco fea.(El objetivo es obtener cada par de funciones en un archivo separado, para reducir los tiempos de compilación y hacer que el código sea más fácil de administrar). ¿Alguien tiene una solución C++ más elegante como alternativa a una matriz de funciones?La velocidad no es realmente un problema, lo que me preocupa más es la mantenibilidad.

-Nicolás

¿Fue útil?

Solución

Podrías escribir algo como:

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);

Podrías usar operator() en lugar de Run como nombre de la función, si lo prefiere.

Otros consejos

¿Qué pasa con la matriz de funciones?

Necesita llamar funciones por índice.Por lo tanto, deben colocarse en alguna estructura "indexable por índice". de alguna manera.Array es probablemente la estructura más simple que se adapta a esta necesidad.

Ejemplo (escribiendo fuera de mi cabeza, es posible que no se pueda compilar):

struct FunctionPair {
   EncodeFunction encode;
   DecodeFunction decode;
};
FunctionPair g_Functions[] = {
   { MyEncode1, MyDecode1 },
   { MySuperEncode, MySuperDecode },
   { MyTurboEncode, MyTurboDecode },
};

¿Qué es "feo" o "difícil de mantener" en el enfoque anterior?

Un objeto con un método operator() definido puede actuar de manera muy parecida a una función, pero en general es más agradable trabajar con él.

El polimorfismo podría ser la solución:Podrías seguir el patrón de estrategia, considerando cada estrategia para implementar una de tus funciones (o un par de ellas).

Luego cree un vector de estrategias y utilícelo en lugar de la lista de funciones.

Pero, francamente, no veo el problema con la matriz de funciones;puede crear fácilmente un typedef para facilitar la legibilidad.Efectivamente, terminará con exactamente la misma estructura de archivos cuando utilice el patrón de estrategia.

// 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 };
  • La declaración de función y las definiciones están en archivos separados; el tiempo de compilación es correcto.
  • La agrupación de funciones está en un archivo separado y depende únicamente de las declaraciones.

Podrías echarle un vistazo a Biblioteca Boost.Signals.Creo que tiene la capacidad de llamar a sus funciones registradas mediante un índice.

Prueba la clase Loki::Functor.Más información en CodeProject.com

Necesita utilizar una serie de punteros de función.El único inconveniente es que todas las funciones deben tener básicamente el mismo prototipo, solo el nombre de la función y los nombres de los argumentos pasados ​​pueden variar.El tipo de retorno y los tipos de argumentos (así como el número de argumentos y el orden) deben ser idénticos.

int Proto1( void );
int Proto2( void );
int Proto3( void );

int (*functinPointer[3])( void ) =
{
   Proto1,
   Proto2,
   Proto3
};

Entonces puedes hacer algo como esto:

int iFuncIdx = 0;
int iRetCode = functinPointer[iFuncIdx++]();

Si miraras dentro boost::signals biblioteca, verás un ejemplo muy bonito, que es muy elegante:
Supongamos que tiene 4 funciones como:

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;
}

Luego, si quieres llamarlos de forma elegante, prueba:

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);

Y la salida es:

The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top