joi, 15 decembrie 2011

Pointeri de functii in c++

Asa cum am promis, voi continua tutorialul in 3 parti necesar crearii unei clase de Timer in c++/Linux. Astazi am sa va arat lucrul cu pointerii de functii(apelul indirect al acestora si transmiterea lor).

La ce se folosesc?
Pai in primul rand, se impune problema apelarii unei functii nedeterminate dintr-un event. Pentru aceasta nu poate fi scrisa functia apelata direct din cod, ci pointerul functiei trebuie transmis printr-un parametru. Ideea ce sta la baza tehnicii e ca functia tot o variabila este in definitiv. Ocupa o zona in stiva, poate fi adresata,etc. O observatie importanta este ca atunci cand lucram cu pointeri, trebuie sa avem mare grija la prototipul functiei pe care o pointeaza.

Un mic exemplu:


#include <iostream>
#include <stdlib.h>

using namespace std;

void print()
{
cout<<"Hello!"<<endl;
}

int main()
{
//Definim riguros pointerul
void (*pointer)();
//Asignam riguros pointerul
pointer= &print;
pointer();

void (*pointer2)();
pointer2=pointer; //Pointerii stocheaza adrese si nu valori
pointer2();
/*Dupa cum vedeti, functia a fost apelata in mod indirect prin intermediul unui pointer. Pointerul poate fi copiat in alta variabila fara probleme atata timp cat se respecta prototipul*/

return 0;
}



Acesta a fost modul riguros de creare si asignare a pointerilor functiilor. Sa trecem la lucruri putin mai serioase, ca de exemplu transmiterea parametrilor prin intermediul pointerilor. O sa radeti, dar chiar este simplu. Avand in vedere ca pointerul nu face decat sa apeleze o anumita zona de memorie, sintaxa este identica cu cea normala.
De ex:
#include <iostream>
#include <stdlib.h>

using namespace std;


void print(char *c)
{
cout<<c<<endl;
}

int main()
{
//Definim riguros pointerul
void (*pointer)(char *);
//Asignam riguros pointerul
pointer= &print;
pointer("Hello!");


/*Dupa cum vedeti, functia a fost apelata in mod indirect prin intermediul unui pointer. Pointerul poate fi copiat in alta variabila fara probleme atata timp cat se respecta prototipul*/

return 0;
}

De remarcat este prototipul!

In continuare vom vorbi despre transmiterea pointerilor ca si parametru. Sintaxa nu e diferita de cea folosita in cazul tipurilor de date "normale". Prin urmare voi da 2 exemple(unul in care voi folosi o functie fara parametrii si unul cu parametrii:

#include <iostream>
#include <stdlib.h>

using namespace std;

void test(void (*print)())
{
print();
}
void print()
{
cout<<"Hello"<<endl;
}
void print2()
{
cout<<"Hello2"<<endl;
}

int main()
{
//Definim riguros pointerul
void (*pointer)();
//Asignam riguros pointerul
pointer=&print;
test(pointer);

pointer=&print2;
test(pointer);
/*Asta e frumusetea pointerilor.
Dupa cum vedeti, 2 functii cu acelasi prototip dar total diferite(instructiuni) au fost apelate prin intermediul aceluiasi pointer de aceeasi functie fara a fi modificata. Ce inseamna asta? Codul nu trebuie modificat pentru fiecare conditie in parte, ci doar transmis un pointer in functie de necesitati.
Observatie: Am putut folosi acelasi pointer datorita aceluias prototip, altfel trebuia creat unul nou.*/
return 0;
}

 
////////////////////////////////////////////////////////////////////////////////////////////////////////////


#include <iostream>
#include <stdlib.h>

using namespace std;

void test(void (*print)(int),int val)
{
print(val);
}
void print(int x)
{
cout<<x<<endl;
}


int main()
{
//Definim riguros pointerul
void (*pointer)(int);
//Asignam riguros pointerul
pointer=&print;
test(pointer,5);
/*Am transmis pe langa pointer si valoarea parametrului. De asemenea se pot transmite pointeri catre array-uri pentru folosirea vectorilor*/
return 0;
}


Transmiterea unui vector de pointeri.
Atentie! Trebuie sa aiba aceleasi prototipuri functiile transmise.

#include <iostream>
#include <stdlib.h>

using namespace std;

void test(void (**print)())
{
for(int i=0;i<2;i++)
print[i]();
}
void print()
{
cout<<"Hello1"<<endl;
}

void print2()
{
cout<<"Hello2"<<endl;
}

int main()
{
//Definim riguros pointerul
void (*pointer[2])();
//Asignam riguros pointerul
pointer[0]=&print;
pointer[1]=&print2;
test(pointer);
/*Am apelat 2 functii cu acelasi cod:)*/

return 0;
}


In urmatorul post voi finaliza clasa de Timer asemanatoarea celei din C#. Asa ca fiti cu ochii pe blog:)


Niciun comentariu:

Trimiteți un comentariu