II. Fonctions Membre
(suite)

  1. Cas des objets transmit en argument d'une fonction membre :

Jusqu'ici les fonctions membre ne recevaient que deux types d'arguments :

 

Nous pouvons passer en argument à une fonction membre d'une classe un objet de cette même classe. Supposons que nous ayons besoin d'une fonction permettant de dire si deux points coïncide(même cordonnées). Nous utiliserons pour cela une fonction membre nommé coincide le premier argument sera implicite car c'est celui qui va faire l'appel de la fonction le deuxième sera explicite, il sera passé en paramètre dans l'appel de la fonction :

point a;
point b;

a.coincide(b);

La déclaration de la fonction coincide sera :

void point::coincide(point pt)

Dans coincide nous aurons à comparer les coordonnées des deux point et de dire si oui ou non il sont égaux :

if ( (pt.x==x) && (pt.y==y) )
	return 1;
else return 0;

Dans l'exemple pt.x représente la coordonnée x de l'objet pt passé en paramètre, tandis que x représente la coordonnée de l'objet implicite.

Voici un exemple de programme ou nous avons limité la classe point à un constructeur et à la fonction coincide :


#include <iostream.h>
class point
	{
	 int x,y;

  public:
	 point (abs=0,ord=0){x=abs;y=ord}  //constructeur "en ligne"
	 int coincide(point);
	
	};

int point::coincide(point pt)
	{
	 return( (pt.x==x) && (pt.y==y) );
	}

void main()
 {
  point a, b(1), c(1,0);
  cout<<"a et b: "<<a.coincide(b)<<"ou "<<b.coincide(a)<<endl;
  cout<<"b et c: "<<b.coincide(c)<<"ou "<<c.coincide(b)<<endl;
 }

a et b: 0 ou 0
b et c  1 ou 1

On pourrait penser que l'on viole le principe d'encapsulation des données en accédant aux données de b lors de l'appel a.coincide(b) car b est un argument explicite. En fait C++ permet a toute fonctions membre d'accéder à toutes les données membre(publique ou privée) de la classe à laquelle il appartienne, l'unité de protection est la classe et non l'objet.

 

  1. Mode de transmission des objets en argument :
  1. Transmission de l'adresse d'un objet :

Nous pouvons transmettre l'adresse d'un objet a une fonction membre explicitement; ici on se contente de transmettre une valeur qui se trouve etre une adresse et qu'il faudrait interpréter comme tel(avec l'utilisation de l'opérateur d'indirection *). Voici comment nous pourrions modifier notre fonction coincide :

int point::coincide(point *pt)
	{
	 return( (pt->x==x) && (pt->y==y) );
	}

L'appel de coincide au sein d'un programme se ferait :

a.coincide(&b);

N'oubliez pas que dés que vous fournissez l'adresse d'un objet à une fonction membre celle-ci peut en modifier la valeur. Pour empêcher cela vous pouvez utiliser le qualificatif const :

int coincide(const point*); //déclaration dans la classe
int point::coincide(const point *pt) //définition de la fonction
	{
	 return( (pt->x==x) && (pt->y==y) )
	}
  1. Transmission par référence :

La transmission par référence permet de transmettre l'adresse d'un objet mais en laissant le soin au compilateur de le géré.

int coincide(point&); //déclaration dans la classe
int point::coincide(point &pt) //définition de la fonction
	{
	 return( (pt.x==x) && (pt.y==y) )
	}
  1. Cas ou la valeur de retour d'une fonction est un objet :

Ce que nous venons de faire pour les arguments d'une fonction s'applique aussi à sa valeur de retour. Il peut s'agir d'un objet et on a donc le choix entre :

Cette objet pourra être :

La transmission par valeur pose les même problèmes que tout a l'heure, a savoir qu'il n'y a qu'une simple recopie des valeurs et que donc il y aura un problème pour les parties dynamiques de la classe.

En revanche pour la transmission par adresse ou par référence se pose un nouveau problème, en effet si l'objet de retour, qui est transmit par la fonction, est un objet de type automatique, alors il sera détruit a la fin de la fonction et l'adresse passée ne sera plus bonne car la place mémoire ne contient plus exactement l'objet de retour.

exemple avec la fonction symétrique qui retourne le symétrique d'un point :

point point::symetrique ()
	{
	 point res;
	 res.x=-x;
	 res.y=-y;
	 return res;
	}
  1. Auto-référence: le mot clé this :

Nous avons vu que lorsque nous appelons une fonction membre l'adresse de l'objet avec lequel nous avons appelé la fonction était transmit implicitement à cette fonction. Nous pouvons dan cette fonction et uniquement dedans utilisé le mot clé this qui permet d'accédé à l'adresse mémoire de l'objet. Si par exemple nous utilisions une liste chaînée d'objets d'une même classe, la fonction membre qui ajoute un nouvel objet à la classe prendra en argument la liste et utilisera le mot clé this pour donner l'adresse de l'objet à la liste. Le mot clé this désigne un pointeur sur l'objet l'ayant appelé.

Il serait prématuré de développé l'exemple de la liste chaîné maintenant, nous allons donc revenir à un exemple d'école en modifiant la fonction membre affiche, pour lui faire afficher l'adresse mémoire de l'objet puis ses cordonnées :


#include <iostream.h>
class point
	{
	 int x,y;

  public:
	 point (abs=0,ord=0){x=abs;y=ord}  //constructeur "en ligne"
	 void affiche();
	
	};

void point::affichep()
	{
	 cout<<"adresse :"<<this<<"je suis en :"<<x<<" "<<y<<endl;
	}

void main()
 {
  point a, b(1,5);
  a.coincide();
  b.coincide();
 }

adresse :0x40d80ffc je suis en :0 0
adresse :0x40d80ff8 je suis en :1 5

Nous aurions aussi put utiliser les données x et y avec le pointeur this :

void point::affiche()
	{
	 cout<<"adresse :"<<this<<this->x<<" "<<this->y<<endl;
	}