Fonctions
Table de matière
Rappel des bases
L’objectif de cette section est rappeler (aussi introduire) les notions de codage de base en C++.
fonctions
Que vous utiliser le paradigme procédural ou Orienté objet, vous aurez
besoin de développer des fonctions
.
Une fonction est un groupe d’instructions pour compléter une tâche.
- La tâche d’une fonction doit être simple pour simplifier la réutilisation.
- Le code d’une fonction ne doit pas généralement dépasser 10 lignes.
Pour illustrer l’utilisation des fonctions, nous proposons de résoudre le problème de décomposition en facteurs premiers
\[n = \prod_{i} p_i ^{r_i}\]où \(p_i\) sont des nombres premiers et \(r_i\) forment leur degrés.
Une modélisation simple de ce problème consiste à implémenter les fonctions suivantes:
bool is_prime (int n)
: pour vérifier si un nombre est premier.
bool is_prime(int n)
{
auto limit = floor( sqrt(n) ) ;
for(auto div = 2; div<= limit; div++)
if( n % div == 0)
return false;
return true;
}
int order( int n, int facteur)
: pour calculer l’ordre d’un facteur.
int order(int n, int factor)
{
auto count = 0;
while( n % factor == 0)
{
count ++;
n /= factor;
}
return count;
}
void print_decomposition(int n)
: Fonction pour afficher la décomposition.
void decomposition(int n)
{
//premier affichage
cout<<n<<"= ";
//Facteur à tester
auto fact = 2;
//Tant que n contient des facteurs
while( n >1)
{
if( (n % fact == 0) && (is_prime(fact)) )
{
auto r = order(n, fact);
cout<<"("<<fact<<"**"<<r<<") ";
n /= pow(fact, r);
}
fact++;
}
cout<<endl;
}
Comme en Java
, on peut surcharger en modifiant soit:
- Le nombre d’arguments.
- Soit le type de paramètre.
A titre d’exemple supposons qu’on offre l’ensemble des fonctions suivantes:
//F1
float Log();
//F2
int Log(int l);
// F3
float Log(float l);
// F4
float Log(float l, float base);
Ces fonctions peuvent être facilement différentiable par leurs paramètres.
auto v1 = Log(5.5); //F3
auto v2 = Log(5) // F2
auto v3 = Log(3, 3); //F4
auto v4 = Log() //F1
Par contre les deux fonctions suivantes ne peuvent pas coexister.
int Log(int a)
float Log(float b) //Problème
Vu que la seule différence entre eux est la valeur de retour.
</div>
A la différence entre Java, en C++ on peut spécifier des valeurs par défaut a nos arguments.
Considérons alors la déclaration suivante:
void temp(int i=10, float f = 8.8)
C’est une fonction qui prend deux arguments qui possèdent une valeur initiale. Ainsi dans l’appel si on fournit pas une valeur, elle peut être remplacée par sa valeur par défaut. Cependant il faut faire attention à l’ordre comme illustrée dans la figure suivante:
Passage d’arguments
En C++, il existe trois mode de passage d’arguments:
- Par copie (défaut)
- Par référence.
- Par adresse
Pour illustrer la différence entre ces modes, considérons l’exemple d’une fonction double la valeur de son argument.
#include <iostream>
using namespace std;
//Function to double the value of its argument
int doubleValue(int x)
{
x *= 2;
return x;
}
int main(int argc, char *argv[])
{
int myValue = 5;
int result = doubleValue(myValue);
cout << myValue << endl; // myValue will not change
cout << result << endl;
return 0;
}
Comparons maintenant l’exécution avec un passage par référence.
//Function to double the value of its argument
int doubleValue(int & x)
{
x *= 2;
}
- Avec ce type de passage, on as pas besoin de renvoyer la valeur doublée.
- Avec des références, C++ pour permet de modifier vos arugments sans copier les données.
- Avec ce type de passage, il faut faire attention.
-
Ce type de passage est souvent recomandé pour passer des arguments lourds en mémoire comme les vecteurs.
- Dérnier point, pour les fonctions de passage par référence, il faut passer une variable. A titre d’exemple, l’appel suivant donnera une erreur
doubleValue(15) // Expect an l-value???
On présentera le troisième mode de passage d’arguments une fois on introduit les pointeurs
Structures
Une structure en C++ est un groupement de données nommées pour représenter un nouveau type.
Prenons par exemple, l’instance Etudiant
dans une base de données. Elle sera
représenté par
- name (
string
) - state (
string
) - age (
int
)
On pourra déclarer cette structure en C++ par le mot clé struct
.
struct Student {
string name; //Attribut ou Field
string state;
int age;
};
//Utilisation
Student S;
S.name = "Karim"; //. pour accéder aux champs
S.state = "Fes";
S.sage = 19;
L’utilisation des structures nous permet de regrouper des informations. Par
exemple pour afficher les informations d’un étudiant on passe une seule
référence Student
au lieu de passer chaque champs.
void printStudentInfo(Student S)
{
cout<<S.name<<" From "<< S.state<<" ( "<<S.age<<" )"<<endl;
}
On peut aussi initialiser les champs d’une structure par
l’opérateur {}
Student S = {"Imad", "Fes", 19}; //Il faut attention à l'ordre
Structure Pair
- Une
pair
est une structure avec deux attributs.- first
- second
- Cette structure est un
template
(generic in Java), ce qui vous permet de controller le type de ces champs. - Pour utiliser
pair
il faut inclure son entêteinclude<utility>
//Déclaration d'une simple pair d'entiers
pair<int, int> point;
//Accéder aux champs
point.first = 3;
point.second = 4;
On peut utiliser l’intialisation uniforme pour donner des valeurs directes aux champs.
//Déclaration d'une simple pair d'entiers
pair<int, int> point{4,5}
//Afficher les valeurs
cout<<point.first<<", "<<point.second<<endl;
Aussi on peut combiner auto
et l’opérateur []
pour extraire facilement le
contenu des deux variables.
//Déclaration d'une simple pair d'entiers
pair<int, int> point{4,5}
//Extraction des valeurs
auto [x, y] = point;
//Afficher les valeurs
cout<<x<<", "<<y<<endl;
Une méthode très utile est la fonction make_pair
qui est une fonction
générique qui permet de créer une pair sans la spécéfication des types.
//Déclaration d'une simple pair d'entiers
auto point = make_pair(22, 33);
//Extraction des valeurs
auto [x, y] = point;
//Afficher les valeurs
cout<<x<<", "<<y<<endl;
- Pour un ensemble de méthodes disponible pour la structure pair. Voir la page officielle documentation pair
- Si on veut stocker plusieurs valeurs en même temps, C++, offre aussi la structure Tuple
- Les pair sont souvent utilisés pour écrire des fonctions qui renvoient plusieurs valeurs. Pour illustrer ce principe, développons la fonction classique pour la résolution d’une équation de second ordre dans \(\mathbb{R}\).
Ainsi, votre tache est de développer une fonction
pair<bool, pair<double, double> > quadratic(int a, int b, int c)
Cette fonction renvoie une pair qui indique si une solution existe ou non. Si oui la deuxième valeur contient les deux solutions.
Solution dans la démo.
Includes
-
Comme C++ est base sur C, il utilse des
entêtes
(header). Un fichier entête maintient générélement des *définitions de fonctions, classes et structures. -
Les fichiers entêtes peuvent faciliter aussi l’étape de compilation de large projets.
- Les fichiers entêtes portent l’extention .h (ou *.hpp).
-
Un point important est que ces fichiers sont généralement inclus en hiérarchie. Un fichier .h qui inclue un autre. Aussi fichier .cpp peut inclure les deux fichiers en même temps. Pour éviter que les fonctions définies deux fois, on utilise:
#pragma once
- Ceci implique que ce fichiers sera inclut une seule fois.
- Voici un exemple simple utilisant un header.
// include_example.h
#pragma once
int square(int x);
bool even(int value);
// include_example.cpp
#include <iostream>
#include "include_example.h"
// On peut appeller les fonctions avant même qu'il soient définie
// Car elle sont dans le fichier entête.
int main() {
cout << square(15) << endl;
if (even(42)) {
cout << "even" << endl;
} else {
cout << "odd" << endl;
}
}
int square(int x) {
return x * x;
}
bool even(int v) {
return v % 2 == 0;
}