Déclaration directe en C++
- Déclaration directe en C++
- Déclaration directe des fonctions en C++
- Déclaration directe des classes en C++
- Pourquoi le compilateur C++ a besoin d’une déclaration avancée
- Avantages de l’utilisation de la déclaration directe en C++
Cet article explique les déclarations directes et montre pourquoi elles sont nécessaires pour le compilateur en C++, ainsi que des exemples de code.
Cela discutera également des avantages de l’utilisation des déclarations directes, mettra en évidence la différence entre une déclaration et une définition, et montrera comment utiliser la déclaration directe pour éviter les erreurs de dépendance cyclique des fichiers C++.
Déclaration directe en C++
Une déclaration directe est la déclaration de la syntaxe d’une fonction, c’est-à-dire son nom, son type de retour, ses arguments et le type de données des arguments avant de l’utiliser dans votre programme.
Avant de définir les fonctions, nous incluons des déclarations directes pour faire savoir au compilateur que la fonction est définie quelque part dans le programme. La déclaration directe des fonctions utilisées dans un fichier séparé est formée en utilisant le #include
pour avoir le fichier.
Déclaration directe des fonctions en C++
Voyons comment fonctionne la déclaration directe dans un extrait de code.
#include <iostream>
using namespace std;
// forward declaration of sub2
int sub2(int A, int B);
int main() {
cout << "Difference: " << sub2(25, 10);
return 0;
}
int sub2(int A, int B) // Defining sub2 here
{
return A - B;
}
Production:
Difference: 15
Ici, nous avons une fonction nommée sub2
qui renvoie la différence de deux paramètres int passés. Nous déclarons sub2
avant la partie principale puis définissons notre fonction plus tard dans le programme.
Avant d’entrer dans l’explication, il est essentiel de connaître la distinction entre définition et déclaration en C++.
Déclaration
: Une déclaration permet de déclarer des informations simples telles que le nom de la fonction, ses arguments et leurs types de données, son type de retour, c’est-à-dire le prototype de la fonction.Définition
: Une définition fournit les détails de la déclaration de la fonction et inclut le bout de code que la fonction de tâche exécuterait.
Revenons maintenant à la déclaration anticipée. Pourquoi la déclaration en avant de sub2
était-elle nécessaire dans le programme ci-dessus ?
Expliquons avec le même code, cette fois, sans utiliser de déclaration forward.
#include <iostream>
using namespace std;
int main() {
cout << "Difference: " << sub2(25, 10);
return 0;
}
int sub2(int A, int B) // Defining sub2 here
{
return A - B;
}
Production:
error : 'sub2' was not declared in this scope 6 | cout << "Difference: "
<< sub2(25, 10);
| ^~~~
Le programme ci-dessus n’a pas de problème mais affiche toujours une erreur indiquant que la fonction sub2
n’a pas été déclarée. C’est parce que sub2
est appelé à la ligne 6 mais n’est défini que plus tard à la ligne 10.
Étant donné que C++ est un langage analysé de haut en bas, il construit un arbre d’analyse à partir du haut et doit connaître à l’avance les fonctions avant de les utiliser. Vous n’avez pas besoin de définir la fonction avant qu’elle ne soit appelée, mais vous devez la déclarer.
Vous pouvez aussi définir une fonction, ici sub2
, avant la fonction principale pour éviter de telles erreurs. Cependant, dans un programme avec plusieurs fonctions qui s’appellent les unes les autres ou des fichiers inclus en externe, l’erreur persisterait, c’est pourquoi nous utilisons des déclarations directes.
Déclaration directe des classes en C++
Vous avez également besoin d’une déclaration directe des classes en C++. Montrons comment.
#include <iostream>
using namespace std;
// Forward declaration of classes One and Two
class One;
class Two;
class One {
int y;
public:
void num(int a) // Getting input number
{
y = a;
}
friend int sub2(One, Two);
};
class Two {
int x;
public:
void num(int a) // Getting input number
{
x = a;
}
friend int sub2(One, Two);
};
int sub2(One a, Two b) // Subtraction of two numbers from both classes
{
int ans = a.y - b.x;
return ans;
}
int main() {
Two y;
One x;
x.num(25);
y.num(10);
cout << "Difference: " << sub2(x, y);
return 0;
}
Production:
Difference: 15
L’extrait de code ci-dessus contient les classes One
et Two
, toutes deux avec une fonction num
pour obtenir une valeur et une fonction sub2
pour soustraire deux nombres.
La déclaration directe des deux classes est nécessaire pour le programme ci-dessus puisque la classe One
inclut la fonction amie sub2
avec la classe Two
mentionnée dans son paramètre.
Si nous supprimons la déclaration directe des classes dans l’extrait de code ci-dessus, nous obtenons un message d’erreur :
15 | [Error] 'Two' has not been declared In function 'int sub2(One, Two)':
L’erreur indique que le compilateur a besoin d’une déclaration directe des fonctions et des classes avant de les utiliser dans un programme.
Pourquoi le compilateur C++ a besoin d’une déclaration avancée
La déclaration forward est nécessaire car elle aide le compilateur à assurer 3 choses :
- Le programme est correct et sans fautes d’orthographe.
- Les arguments de la fonction déclarée sont corrects.
- La fonction déclarée existe dans le programme et est définie ci-dessous.
Si vous n’aviez pas déclaré les fonctions, le compilateur créerait un fichier objet supplémentaire contenant des informations avec diverses suppositions sur ce que pourrait être votre fonction.
Et l’éditeur de liens (un programme qui relie plusieurs objets et classes dans un seul fichier objet exécutable) aurait un problème de liaison, car il pourrait avoir une fonction existante du même nom mais avec des arguments d’un type de données différent.
Par exemple, supposons que vous ayez une fonction int sub2(int a, int b)
. Sans la déclaration forward, l’éditeur de liens pourrait être confondu avec une autre fonction existante int sub2(float a, float b)
.
Un compilateur valide le code d’un fichier propre avec une déclaration directe C++. Il serait préférable de se rappeler que C++ peut compiler et exécuter un tel programme dans certains cas.
Cependant, cela ne fournirait pas le résultat attendu. C’est pourquoi le compilateur requiert des déclarations directes avant de les implémenter ou de les utiliser dans votre code.
Avantages de l’utilisation de la déclaration directe en C++
Les déclarations directes aident le compilateur à mieux valider votre code et à éviter les problèmes de liaison. Mais ça aide aussi :
-
Évitez de polluer l’espace de noms : les déclarations directes permettent de s’assurer qu’aucun extrait de code n’est égaré et d’éviter de polluer un espace de noms.
-
Améliorer le temps de compilation : vous pouvez ajouter la déclaration d’une fonction dans votre programme C++ en incluant un fichier d’en-tête, et le compilateur analysera tous les jetons fournis dans le fichier, ce qui peut prendre beaucoup de temps. Cependant, vous pouvez éviter ce long traitement et utiliser la déclaration directe pour les classes particulières que vous avez l’intention d’utiliser au lieu du fichier
cpp
entier.Cela peut ne pas avoir d’impact sur les codes plus petits, mais s’avérer utile dans des projets plus importants car cela peut minimiser les temps de compilation, réduisant ainsi la complexité temporelle. Ainsi, au lieu d’inclure un fichier C++ entier, vous pouvez utiliser une classe spécifique avec l’extension
.h
. -
Évitez les collisions de noms : les déclarations directes permettent également de garantir qu’il n’y a pas de collision de noms de jeton ou de préprocesseur dans le programme s’il existe différents projets avec des noms de fonction ou de classe correspondants.
-
Rompre la dépendance cyclique : la déclaration directe d’une classe peut résoudre les références cycliques en déclarant les parties particulières nécessaires dans un fichier et en laissant l’en-tête en dehors de celui-ci.
Éviter la dépendance circulaire à l’aide de la déclaration directe en C++
Deux classes liées ou utilisant les fonctions de l’autre créent une relation circulaire. C’est ce qu’on appelle la dépendance cyclique ou circulaire.
Supposons qu’il y ait deux classes dans votre programme où les deux doivent utiliser l’autre. Dans ce cas, vous ajouterez un fichier d’en-tête pour l’un, mais il essaiera en outre d’inclure le fichier d’en-tête pour l’autre classe dépendante circulairement, créant un cycle où chaque en-tête essaie d’avoir l’autre.
Voyons comment éviter la dépendance cyclique :
#include <iostream>
#include <vector>
#include "Two.h" // Defining Two as it is used in One
class One {
std::vector<Two> two;
};
int main() { return 0; }
Notre programme a inclus un autre fichier nommé Two.h
en utilisant #include
tel qu’il est utilisé dans la classe One
. Inclure un fichier class.h
et non tout un autre programme réduit considérablement les temps de compilation, comme expliqué ci-dessus.
Maintenant, regardez le contenu de Two.h
.
#include "One.h" // Defining One as it is used in Two
class Two {
One* a; // Two uses a pointer of One
};
Two.h
contient la classe Two
qui utilise un pointeur de classe One
. Mais puisque les deux fichiers contiennent des en-têtes pour inclure l’autre fichier, vous serez coincé dans une dépendance circulaire où les deux fichiers continuent de s’appeler. Cela peut être évité en utilisant une déclaration directe au lieu d’ajouter un en-tête dans Two.h
en :
#include <iostream>
class One;
class Two {
One* a; // Two uses a pointer of One
};
Il serait préférable de se rappeler que la déclaration directe d’une fonction nécessite la connaissance du nom de la fonction et des arguments qui seront utilisés lors de sa définition et nécessite la duplication des valeurs par défaut pour les paramètres par défaut.
Par conséquent, vous devez faire attention lorsque vous utilisez la déclaration vers l’avant dans vos programmes.