2013-02-28 11 views
10

Va bene, a mio principale che ho:C++ chiamando una funzione da un vettore di puntatori a funzione all'interno di una classe in cui la definizione di funzione è in main

void somefunction(); 
int main() 
{ 
    //bla bla bla 
    SomeClass myclass = SomeClass(); 
    void(*pointerfunc)() = somefunction; 
    myclass.addThingy(pointerfunc); 

    //then later i do 
    myclass.actionWithDiffrentOutcomes(); 
} 

void somefunction() 
{ 
    //some code 
} 

e nella classe:

class SomeClass() 
{ 
    public: 
     void addThingy(void (*function)()); 
     void actionWithDiffrentOutcomes(); 
    private: 
     std::vector<void (**)()> vectoroffunctions; 
} 
SomeClass::addThingy(void (*function)()) 
{ 
    vectoroffunctions.push_back(&function); 
} 
SomeClass::actionWithDiffrentOutcomes() 
{ 
    (*vectoroffunctions[0])();; 
} 

Sono una sorta di new-ish per i puntatori, ma ho letto i miei libri C++, googled, ext. e questo sembra corretto, compila, ma quando chiamo "actionWithDiffrentOutcomes()" ottengo una violazione di accesso. Non sono sicuro di cosa fare. sembra corretto, ma qualcosa è ovviamente sbagliato. Quindi, come posso chiamare una funzione all'interno di una classe quando la definizione è in un'altra?

Lo sto facendo in questo modo perché non riesco a codificare tutte le opzioni in un'istruzione switch.

+0

Il codice di esempio non viene compilato; potresti per favore ricontrollare la sintassi e modificare la tua domanda? – congusbongus

+0

Questo codice non verrà compilato. Fornire un [Breve, autonomo, corretto (compilabile), esempio] (http://sscce.org/). – Johnsyweb

risposta

12

Il codice è quasi corretto. Il tuo vettore sta erroneamente tenendo puntatori a puntatori a funzioni piuttosto che a semplici puntatori a funzioni. addThingy sta aggiungendo l'indirizzo del puntatore function allo vector, ma tale puntatore non rientra nell'ambito della riga successiva.

modificare il codice come segue:

//Store pointers to functions, rather than 
//pointers to pointers to functions 
std::vector<void (*)()> vectoroffunctions; 

SomeClass::addThingy(void (*function)()) 
{ 
    //Don't take the address of the address: 
    vectoroffunctions.push_back(function); 
} 

Inoltre, si hanno un sacco di errori di sintassi nel resto del codice che dovrebbe fermare il codice anche da compilare.

+0

Ah grazie, ha più senso. Inoltre, mi dispiace per la sintassi, l'ho copiato in np ++ per postarlo qui piuttosto che pubblicare il mio intero programma. –

5

Il problema è qui:

vectoroffunctions.push_back(&function); 

Stai salvando l'indirizzo della variabile locale. La variabile locale viene distrutta una volta che si ritorna dalla funzione. L'indirizzo che il vettore memorizza fa riferimento a un oggetto distrutto, motivo per cui si ottiene "violazione di accesso" errore in fase di esecuzione.

Per risolvere questo problema, fare questo:

Primo cambio questo

std::vector<void (**)()> vectoroffunctions; 

a questo:

std::vector<void (*)()> _functions; //vector of function-pointer-type 
            //I changed the name also! 

che è praticamente uguale:

std::vector<void()> _functions; //vector of function-type 

Ora fare questo:

_functions.push_back(function); //add copy! 

Per renderlo più flessibile, è possibile utilizzare template con std::function come:

class A 
{ 
    public: 
     template<typename Function> 
     void add(Function && fn) 
     { 
      _functions.push_back(std::forward<Function>(fn)); 
     } 
     void invoke_all() 
     { 
      for(auto && fn : _functions) 
       fn(); 
     } 
    private: 
     std::vector<std::function<void()>> _functions; 
}; 

Ora è possibile utilizzarlo per memorizzare funzioni così come funtori:

void myfunction() { std::cout << "myfunction" << std::endl ; } 

struct myfunctor 
{ 
     void operator()() { std::cout << "myfunctor" << std::endl ; } 
}; 

A a; 
a.add(myfunction); //add function 
a.add(myfunctor()); //add functor! 
a.invoke_all(); 

Uscita (Online Demo):

myfunction 
myfunctor 

Spero che questo aiuti.

+0

Qualche soluzione elegante per funzioni con argomenti variabili? –

+0

@sid: qual è il caso d'uso? – Nawaz

1

puntatori a funzione sono molto più leggibili con typedefs:

typedef void (*RequiredFunction)(); 

Quindi è possibile dichiarare addThingy() come questo:

void addThingy(RequiredFunction function); 

E vectoroffunctions in questo modo:

std::vector<RequiredFunction> vectoroffunctions; 

La definizione di addThingy sarà:

void SomeClass::addThingy(RequiredFunction function) 
{ 
    vectoroffunctions.push_back(function); 
} 

E il tuo main() sarebbe più simile:

int main() 
{ 
    SomeClass sc; 
    RequiredFunction pointerfunc = somefunction; 
    sc.addThingy(pointerfunc); 
    sc.actionWithDiffrentOutcomes(); 
} 

molti meno * s e & s con cui fare errori!

Problemi correlati