II. Fonction Membre
(suite)

  1. Les fonctions membre statiques :

Nous avons vu précédemment qu'il existe des données membre statique, c'est à dire indépendant des objets de la classe et n'existant qu'en un seul et unique exemplaire.

Il est possible aussi d'envisager des fonctions membre ayant un rôle indépendant des objets de la classe. Cela pourrait être des fonctions membre utilisé pour travailler sur des membres statiques. Nous pourrions appeler cette fonction avec un objet que nous n'utiliserions pas. Mais il existe un moyen de rendre une fonction membre indépendante des objets de la classe. Pour cela il suffit de déclaré cette fonction en fonction membre statique, le même mot clé static, utilisé pour les données membre statiques, sera placé devant le type de retour de la fonction(void si elle ne retour rien!). Dans ce cas l'appel de fonction ne nécessite plus que le nom de la fonction précédé par le nom de la classe(ainsi que l'opérateur de résolution de porté).

Voici un exemple de programme utilisant une fonction membre statique. C'est le même programme que celui utilisé pour les données membre statique, mais avec une fonction donnant le nombres d'objets courant :


#include <iostream.h>
class cmpt_obj
	{
	 static int nb_obj;
	 
 public:
	 cmpt_obj(); //constructeur
	 ~cmpt_obj(); //destructeur
	 static void compte();
	};

int cmpt_obj::nb_obj=0;  //initialisation de la donnée membre statique

cmpt_obj::cmpt_obj()
   {
    cout<<"++construction, il y a maintenant:   "
		<<++nb_obj<<" objets\n";
   }
 
cmpt_obj::~cmpt_obj()
   {
    cout<<"--destruction,  il reste maintenant: "
		<<--nb_obj<<"objets\n";
   }

void cmpt_obj::compte()
	{
	 cout<<"appel de compte il y a "<<nb_obj<<" objets\n";
	}


void fct(); //déclaration d'une fonction

void main() //programme principale
 {
  cmpt_obj::compte();

  cmpt_obj a;
  cmpt_obj::compte();

  fct();         //appel de fonction
  cmpt_obj b;
  cmpt_obj::compte();
 }

void fct()
 {
  cmpt_obj u,v;
 }


appel de compte il y a 0 objets // appel de compte 
	//alors qu'il n'y a aucun objets de cmpt_obj

++construction, il y a maintenant:   1 objets
  //construction de l'objet a

appel de compte il y a 1 objets
 
++construction, il y a maintenant:   2 objets
  //construction de l'objet u dans la fontion fct()
++construction, il y a maintenant:   3 objets
  //construction de l'objet v dans la fontion fct()

--destruction,  il reste maintenant: 2 objets
  //destruction de l'objet v et u 
--destruction,  il reste maintenant: 1 objets
  //  lors de la sortie de la fonction

++construction, il y a maintenant:   2 objets
  //construction de l'objet b lors du retour au main 

appel de compte il y a 2 objets

--destruction,  il reste maintenant  1 objets
  //destruction de l'objet b lors de la fin du main
--destruction,  il reste maintenant  0 objets
  //destruction de l'objet a lors de la fin du main

  1. Les fonctions membre constantes :

En C++, il existe un qualificatif(mot clé const )qui permet de rendre constante une donnée, c'est a dire qu'une fois initialiser sa valeur ne pourras être modifié ultérieurement :

const int n=20;

L'instruction suivante sera incorrecte :

n=12; //incorrecte

C++ nous permet de généralisé ce concept aux niveaux des classes en pouvant rendre un objet d'une classe constant. Le problème vient du fait que le compilateur à du mal a interpréter les accès interdit de modification d'un objet constant car l'accès aux données membre se fait par les fonctions membre. Il faut donc autoriser l'accès aux niveaux des fonctions membre. Pour cela il faut rendre la fonction membre constante( a l'aide du mot clé const). Ainsi la fonction devient accessible par les objets constants, une fonction non constante ne peut être appelée par un objet statique. Voici un exemple de classe ayant des fonctions constantes :

class point
	{
	 int x,y;
  public:
	 point(int,int);
	 void affiche() const;
	 void deplace(int,int);
		.
		.
		.
	};

Nous avons déclaré une fonction affiche accessible par les objets constants et une fonction deplace qui ne le sera pas. Ainsi les déclarations suivantes :

point a(1,5);
const point b(5,2);

nous permette les appel de fonctions suivant :

a.affiche();
a.deplace(4,2);
b.affiche();

par contre une déclaration tel que celle-ci sera une erreur :

b.deplace(4,5); //erreur

Il est possible de surdéfinir une fonction membre en se basant sur le qualificatif const, ainsi si le l'objet appelant est constant se sera la fonction membre constante qui sera appelé sinon se sera l'autre fonction :

void affiche() const; //affiche I
void affiche(); //afficheII

Attention, un objet constante ne peut appeler une fonction non-constante, par contre un objet normal peut appelé une fonction constante. Dans le doute sûr l'utilisation des objets constants une fonction constante est plus recommandée.

 

  1. Les pointeurs sur des fonctions membre :

En C nous pouvons déclarer des pointeurs sur des variables, ces pointeurs sont des variables contenant l'adresse mémoire d'une variable. Nous pouvons en faire de même avec les fonctions ordinaires que nous déclarons :

int fct1(char,double);
int fct2(char,double);
	.
	.
	.
int (*adr) (char,double);

Ici nous avons deux fonctions fct1 et fct2 qui reçoivent en argument un char et un double et qui retourne un int. Puis nous avons un pointeur sur une fonction recevant en argument un char et un double et retournant un int. Pour affecté une fonction au pointeur sur fonction, on utilise l'opérateur '=' :

adr=fct1;  //affecte l'adresse de la fontion
	   //au pointeur adr, on peut aussi ecrire
adr=fct2;  // adr=&fct1

L'instruction :

(* adr)('c',5.25);

réalise l'appel de la fonction contenue dans adr avec comme argument 'c' et 5.25.

Bien entendus C++ nous offre les mêmes possibilités en l'étendant aux classes. Nous pouvons donc déclarer un pointeur sur une fonction membre sans pour autant oublié l'opérateur de résolution de porté. Ainsi une classe point comportant deux fonctions membre :

void dep_hor(int);
void dep_vect(int);

la déclaration :

void (point::*adr)(int);

précisera que adr est un pointeur sur une fonction membre prenant un argument et ne renvoyant aucune valeur. Nous pouvons faire les affectations suivantes :

adr=point::dep_hor;
adr=dep_vect;

Nous pouvons avoir une instruction du type :

(a.*adr)(3);

Ceci va provoqué l'appel de la fonction contenue dans adr en lui transmettant comme argument la valeur 3.