Sur les forums C++ et particulièrement Qt, je vois passer beaucoup de fichiers d'entête qui contiennent de nombreux #include
qui n'ont rien à faire là.
Ces fichiers d'entête n'ont pas pour but d'inclure les dépendances dont vous aurez besoin dans les fichiers source qui les incluent, ce sont les fichiers sources eux-mêmes qui doivent s'occuper de les inclure, car ce sont eux seuls qui en ont réellement besoin.
Les seuls fichiers à inclure dans les fichiers d'entête sont ceux définissant les types utilisés en son sein-même. Et encore, comme indiqué dans ce sujetLe problème d'inclusion circulaire / la « forward declaration », si les bonnes conditions sont réunies, vous pouvez vous contenter de forward declarations.
Mais en quoi est-ce important ?
Lorsque vous incluez tous ces fichiers dans une entête, le compilateur va, lors de la compilation de chaque unité de compilation qui l'inclut, avoir à tous les parcourir inutilement et mettra donc du temps supplémentaire. Alors que placés dans le fichier source, seule l'unité de compilation concernée les aurait parcourus.
Et ce temps additionnel bien que sans doute négligeable sur votre petit projet, ne le sera certainement pas sur un gros projet.
Cette bonne pratique vous évitera également le problème souvent croisé d'inclusion circulaireLe problème d'inclusion circulaire / la « forward declaration ».
Prenons l'exemple suivant(1) :
#ifndef MAFENETRE_H
#define MAFENETRE_H
#include <QApplication>
#include <QWidget>
#include <QtWidgets>
#include <QPushButton>
#include <QLCDNumber>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "MyLCD.h"
#include "Video.h"
class MaFenetre : public QWidget
{
Q_OBJECT
public :
MaFenetre();
public slots :
void createbutton();
private :
QPushButton * m_minusbutton;
QPushButton * m_plusbutton;
QPushButton * m_addbuttonListener;
QHBoxLayout * m_toplayout;
QVBoxLayout * m_principallayout;
QVBoxLayout * m_layout;
MyLCD * m_lcd;
Video * m_video;
int count;
} ;
#endif
|
#include "MaFenetre.h"
#include <iostream>
using namespace std;
MaFenetre:: MaFenetre() : QWidget ()
{
m_minusbutton = new QPushButton ("-" , this );
m_lcd = new MyLCD();
m_plusbutton = new QPushButton ("+" , this );
m_addbuttonListener = new QPushButton ("add" , this );
m_toplayout = new QHBoxLayout ;
m_toplayout-> addWidget(m_minusbutton);
m_toplayout-> addWidget(m_lcd);
m_toplayout-> addWidget(m_plusbutton);
m_toplayout-> addWidget(m_addbuttonListener);
m_layout = new QVBoxLayout ;
m_principallayout = new QVBoxLayout ;
m_principallayout-> addLayout(m_toplayout);
m_principallayout-> addLayout(m_layout);
setLayout(m_principallayout);
QWidget :: connect (m_minusbutton, SIGNAL (clicked()), m_lcd, SLOT (decrement()));
QWidget :: connect (m_plusbutton, SIGNAL (clicked()), m_lcd, SLOT (increment()));
QWidget :: connect (m_addbuttonListener, SIGNAL (clicked()), this , SLOT (createbutton()));
}
void MaFenetre:: createbutton()
{
for (int i = count; i < count + m_lcd-> value(); i++ ){
Video * m_video = new Video(count);
m_layout-> addWidget(m_video);
}
count += m_lcd-> value();
}
|
#include
<QtWidgets>
: ce fichier, à ne pas confondre avec <
QWidget
>
, inclut TOUTES les entêtes des classes qui composent le module Qt Widgets. Autant dire que son inclusion et très pénalisante et complètement inutile ;
#include
<QApplication>
: aucun élément qu'il définit n'est utilisé, que ce soit dans le .h ou dans le .cpp. Tout simplement inutile (d'autant que le point précédent l'incluait déjà) ;
#include
<iostream>
dans le fichier source (ainsi que using
namespace
std;) : idem son contenu n'est pas utilisé, son inclusion est inutile ;
#include
<QLCDNumber>
: aucune utilisation ici non plus, sa place est plutôt dans le fichier MyLCD.h ou le fichier source selon le contenu.
Nous arrivons maintenant à la partie intéressante. En voyant les membres :
QPushButton
*
m_minusbutton;
QPushButton
*
m_plusbutton;
QPushButton
*
m_addbuttonListener;
QHBoxLayout
*
m_toplayout;
QVBoxLayout
*
m_principallayout;
QVBoxLayout
*
m_layout;
MyLCD *
m_lcd;
Video *
m_video;
vous pourriez vous dire que nous avons besoin d'inclure les éléments suivants :
#include
<QPushButton>
#include
<QGridLayout>
#include
<QHBoxLayout>
#include
<QVBoxLayout>
#include
"MyLCD.h"
#include
"Video.h"
Mais aucun de ces fichiers n'a réellement besoin d'être inclus. Vu que nos membres sont des pointeurs (à nouveau, je vous renvoie vers ce sujetLe problème d'inclusion circulaire / la « forward declaration »), nous pouvons économiser ces inclusions et seulement forward-déclarer ces classes dans le .h ; puis inclure ces fichiers dans le .cpp où là seulement on aura besoin de leur définition :
class QPushButton ;
class QHBoxLayout ;
class QVBoxLayout ;
class MyLCD;
class Video;
|
#include <QPushButton>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "MyLCD.h"
#include "Video.h"
|
Pour finir, le seul fichier nécessaire, car la classe ici définie en hérite : #include
<QWidget>
.
Les deux fichiers deviennent alors :
#ifndef MAFENETRE_H
#define MAFENETRE_H
#include <QWidget>
class QPushButton ;
class QHBoxLayout ;
class QVBoxLayout ;
class MyLCD;
class Video;
class MaFenetre : public QWidget
{
} ;
#endif
|
#include "MaFenetre.h"
#include <QPushButton>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "MyLCD.h"
#include "Video.h"
|
Notez que les fichiers tels que :
#include
<stdio.h>
#include
<stdlib.h>
#include
<math.h>
sont des entêtes du langage C, pas du C++. En C++ on utilise ceux avec un « c » devant et sans extension :
#include
<cstdio>
#include
<cstdlib>
#include
<cmath>
(Les deux premiers étant souvent inclus inutilement en C++.)