| ||
auteur : Aurélien Regat-Barrel | ||
Quand une fonction membre (non statique) d'une classe ne modifie pas cette dernière, il est judicieux en C++ de la rendre constante en ajoutant le mot-clé const à la fin de son prototype. Cela rappelle que cette fonction ne modifie et ne doit pas modifier l'objet ce qui permet de l'utiliser sur des objets constants en plus d'aider le compilateur à effectuer des optimisations.
Dans l'exemple précédent, si la fonction membre F() const n'existait pas, on n'aurait pas pu appeler F() sur l'objet t2. Notez que le fait d'avoir rajouté le mot clé const a provoqué une surcharge de la fonction F() au même titre qu'une surcharge effectuée avec un nombre de paramètres différents. |
| ||
auteurs : LFE, Aurélien Regat-Barrel | ||
Une fonction membre déclarée static a la particularité de pouvoir être appelée sans devoir instancier la classe. Elle ne peut utiliser que des variables et des fonctions membres static elles aussi, c'est-à-dire qui ont une existence en dehors de toute instance.
|
| |||
auteur : Laurent Gomila | |||
On parle de masquage de fonction lorsqu'on définit dans une classe dérivée une fonction de même nom qu'une fonction d'une classe
de base, mais avec un prototype différent. Voici un exemple qui illustre ce problème :
Dans cet exemple, la fonction F de la classe de base n'est non pas surchargée mais masquée, ce qui signifie qu'elle n'est plus
accessible dans la classe dérivée. Pour palier ce problème il suffit d'utiliser la directive using pour réimporter la
fonction masquée dans la portée de la classe dérivée :
On peut également régler le problème en spécifiant explicitement lors de l'appel d'où vient la fonction que l'on souhaite utiliser :
|
| ||
auteur : Laurent Gomila | ||
En C++, il est possible de passer des pointeurs de fonctions en paramètre d'autres fonctions. Mais peut-être aurez-vous remarqué que le compilateur râle parfois lorsque vous essayez de passer un pointeur sur fonction membre. Voici un exemple courant, la création de threads (sous Windows) :
Pourquoi ce code ne compile pas avec une fonction membre ? Parce que le type de Fonction1 et MaClasse::Fonction2 n'est pas le même.
La fonction globale Fonction1 a pour type DWORD (*)(void*). La fonction membre Fonction2 a pour type DWORD (MaClasse::*)(void*). On comprend facilement cette différence, étant donné que Fonction2 aura besoin d'une instance de MaClasse pour être appelée, au contraire de Fonction1 qui pourra être appelée "librement". A noter que le type des fonctions membres statiques peut être assimilé à celui des fonctions globales, puisque celles-ci peuvent être également appelées sans instance de la classe. Ainsi pour contourner le problème, il faudrait (par exemple) procéder ainsi :
A noter qu'on peut tout à fait demander à une fonction de recevoir comme paramètre un pointeur sur fonction membre, il suffit d'indiquer le bon type, comme expliqué ci-dessus.
|
| |||
auteur : Laurent Gomila | |||
En C, il est possible de déclarer une fonction acceptant un nombre de paramètres variables via "..." (c'est ce qu'on appelle l'ellipse).
L'exemple le plus connu est celui de la fonction d'affichage printf.
En C++ il est bien entendu toujours possible d'utiliser cette méthode mais il y a mieux : le chaînage d'appels. Les avantages sont
multiples :
Cette méthode est intensivement utilisée par exemple pour manipuler les flux standards :
On peut également imaginer d'autres formes de chaînages pour d'autres applications :
Comme vous le voyez, ce qui rend possible le chaînage est le renvoi de l'instance courante par la fonction. Ainsi, Poly.Add(x, y) renvoie
Poly, sur lequel on peut de nouveau appeler Add etc...
|
| |||
auteur : Laurent Gomila | |||
Par défaut les paramètres de fonctions sont passés par valeur, c'est-à-dire que c'est une copie du paramètre passé qui est manipulée
par la fonction et non l'original. Cela peut paraître anodin lorsqu'il s'agit de passer un type de base, mais cela devient vite pénalisant
lorsqu'il s'agit d'une instance de classe dont la copie peut s'avérer coûteuse (par exemple un vector de string). Cela peut également être
un problème si l'on souhaite passer en paramètre une classe qui n'est tout simplement pas copiable (par exemple un flux standard). Pour
régler le problème, on utilise ainsi ce qu'on appelle le passage par référence ou par référence constante. En passant une
référence, on s'assure que c'est l'objet initial qui est manipulé dans la fonction et donc qu'aucune recopie indésirable n'est effectuée.
En passant une référence constante, on s'assure également que notre paramètre ne pourra pas être modifié par la fonction. Une bonne
habitude est donc de prendre tout paramètre non modifiable par référence constante, excepté les types primitifs. D'autant plus que cela n'a
strictement aucune autre conséquence, ni au niveau de la fonction ni au niveau de l'appelant.
Attention à ne pas oublier le const si le paramètre n'est pas modifié dans la fonction : cela permet en effet de passer ce
que l'on appelle des temporaires non nommés.
Cette remarque vaut également pour les pointeurs :
|
| ||
auteur : LFE | ||
Définir dans une classe une fonction membre qui a le même nom qu'une fonction standard est possible, mais risque de poser problème lors de
l'utilisation de cette fonction membre à l'intérieur de la classe. La fonction membre masque la fonction standard. Il reste toutefois possible d'utiliser la fonction standard en faisant précéder son nom de l'opérateur de résolution de portée ::.
|
| ||
auteur : Aurélien Regat-Barrel | ||
En C++, en general, on evite d'utiliser les fonctions callback au profit d'alternatives un peu plus "objet"
(tel les foncteurs par exemple). Cependant, on est parfois oblige d'y recourir, typiquement pour s'interfacer
avec une autre bibliotheque ecrite en C. Si tel est votre cas, il vous faut alors etre prudent et veiller a ce
que votre fonction callback C++ passee a la bibliotheque C ne leve pas d'exception, surtout si vous l'utilisez
deja compilee (dll). La raison est que les exceptions C++ ne sont pas supportee en C, et les consequences d'une
exception levee dans votre callback C++ et remontant jusqu'au code C appelant peuvent etre facheuses. Et d'une
maniere plus generale, les exceptions posent probleme des qu'il s'agit de franchir les limites d'un module
compile (tel une dll), meme entre differents modules developpes en C++ (ABI incompatibles).
On peut toutefois preciser que sous Windows, un systeme d'exception (Structured Exception Handling, ou SEH) est
integre au sein meme du systeme. Certains compilateurs l'exploitent, y compris en langage C (au moyen de mots cles
specifiques), ce qui permet a du code C d'etre traverse sans probleme par des exceptions lancees depuis un code C++,
si celles-ci ont ete emises sous forme de SEH. Certains compilateurs s'appuient sur SEH pour implementer leurs
exceptions C++ (c'est le cas de Visual C++ par exemple), les rendant ainsi compatibles avec n'importe quel autre code compile. Consultez la documentation de votre compilateur pour plus de details.
|
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.