Domanda

Sto lavorando a un progetto abbastanza complesso, una routine di crittografia personalizzata se vuoi (solo per divertimento) e ho riscontrato questo problema nella progettazione del layout del mio codice.

Ho un numero di funzioni che voglio poter chiamare per indice. In particolare, devo essere in grado di chiamarne uno in modo casuale per il processo di crittografia, ma poi risolverlo tramite un indice specifico nel processo di decrittografia.

Stavo prendendo in considerazione un array di funzioni classico, ma la mia principale preoccupazione è che un array di funzioni sarebbe difficile da mantenere e un po 'brutto. (L'obiettivo è quello di ottenere ogni coppia di funzioni in un file separato, per ridurre i tempi di compilazione e semplificare la gestione del codice.) Qualcuno ha una soluzione C ++ più elegante in alternativa a un array di funzioni? La velocità non è davvero un problema, sono più preoccupato per la manutenibilità.

-Nicholas

È stato utile?

Soluzione

Potresti scrivere qualcosa del tipo:

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

Puoi usare operator () invece di Esegui come nome della funzione, se preferisci.

Altri suggerimenti

Cosa c'è che non va nell'array di funzioni?

È necessario chiamare le funzioni per indice. Quindi devono essere messi in alcuni "indicizzabili per indice" struttura in qualche modo . L'array è probabilmente la struttura più semplice adatta a questa esigenza.

Esempio (digitando dalla mia testa, potrebbe non essere compilato):

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

Che cos'è " brutto " o "difficile da mantenere" nell'approccio sopra?

Un oggetto con un metodo operator () definito può agire in modo molto simile a una funzione ma essere generalmente più carino con cui lavorare.

Il polimorfismo potrebbe fare il trucco: potresti seguire il modello di strategia, considerando ogni strategia per implementare una delle tue funzioni (o una coppia di esse).

Quindi crea un vettore di strategie e usa questo invece dell'elenco delle funzioni.

Ma francamente, non vedo il problema con l'array di funzioni; puoi facilmente creare un typedef per facilitare la leggibilità. In modo efficace, si otterrà esattamente la stessa struttura di file quando si utilizza il modello di strategia.

// 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 dichiarazione di funzione e le definizioni sono in file separati - il tempo di compilazione è ok.
  • Il raggruppamento delle funzioni si trova in un file separato, con una dipendenza solo dalle dichiarazioni

Puoi dare un'occhiata alla Libreria Boost.Signals . Credo che abbia la capacità di chiamare le sue funzioni registrate usando un indice.

Prova la classe Loki :: Functor. Maggiori informazioni su CodeProject.com

È necessario utilizzare una matrice di puntatori a funzione. L'unico problema è che tutte le funzioni devono avere sostanzialmente lo stesso prototipo, solo il nome della funzione e i nomi degli argomenti passati possono variare. Il tipo di ritorno e i tipi di argomento (nonché il numero di argomenti e di ordine) devono essere identici.

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

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

Quindi puoi fare qualcosa del genere:

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

Se hai guardato nella libreria boost :: signal , vedrai un esempio molto bello, molto elegante:
Supponi di avere 4 funzioni come:

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

Quindi se vuoi chiamarli in modo elegante prova:

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

E l'output è:

The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top