===== Le système de méta-objets =====
Le système de méta-objets est basé sur trois choses : **la classe [[QObject]]**, qui fournit une classe de base pour les objets pouvant tirer un avantage du système de méta-objets ; **la macro [[QObject#Q_OBJECT|Q_OBJECT]]**, à l'intérieur de la section privée de la déclaration de classe, qui est utilisée pour activer les dispositifs des méta-objets, comme les propriétés dynamiques, les signaux et les slots ; **le [[moc#moc|compilateur de méta-objets]]** (''moc''), qui munit chaque sous-classe de [[QObject]] du code nécessaire à l'implémentation des dispositifs des méta-objets.
==== Le fonctionnement du système de méta-objets ====
L'outil ''moc'' lit un fichier source C++. S'il trouve une déclaration de classe ou plus qui contient la macro [[QObject#Q_OBJECT|Q_OBJECT]], il produit un autre fichier source C++ contenant le code de méta-objet pour chacune de ces classes. Ce fichier source généré est soit inclus dans le fichier source de la classe, soit, plus communément, compilé et joint avec l'implémentation de la classe.
En plus de fournir le mécanisme de [[signalsandslots|signaux et de slots]] pour la communication entre les objets (la raison principale d'introduction du système), le code de méta-objet fournit les dispositifs suivants :
* [[QObject#metaObject|QObject::metaObject()]], qui retourne le méta-objet associé à la classe ;
* [[QMetaObject#className|QMetaObject::className()]], qui retourne le nom de la classe tel une chaîne de caractères lors de l'exécution, sans nécessiter le support natif d'informations de type disponible à l'exécution (//RTTI//) à travers le compilateur C++ ;
* La fonction [[QObject#inherits|QObject::inherits()]], qui précise si un objet est une instance ou non d'une classe héritant de la classe spécifiée à l'intérieur de l'arbre de l'héritage de [[QObject]] ;
* [[QObject#tr|QObject::tr()]] et [[QObject#trUtf8|QObject::trUtf8()]], qui traduisent des chaînes de caractères pour l'[[internationalization|internationalisation]] ;
* [[QObject#setProperty|QObject::setProperty()]] et [[QObject#property|QObject::property()]], qui définissent et obtiennent dynamiquement les propriétés par nom ;
* [[QMetaObject#newInstance|QMetaObject::newInstance()]] qui construit une nouvelle instance d'une classe.
Il est aussi possible de rendre plus performantes les conversions de types dynamiques en utilisant [[QObject#qobject_cast|qobject_cast()]] sur les classes dérivant de [[QObject]]. La fonction [[QObject#qobject_cast|qobject_cast()]] se comporte de manière similaire au ''dynamic_cast()'' du C++ standard, avec pour avantage de ne pas avoir besoin du support RTTI et de fonctionner à travers les limites des bibliothèques. Il tente de convertir son argument vers le type de pointeurs spécifié entre les chevrons (''<'' et ''>''), retournant un pointeur non nul si l'objet est du type correct (déterminé lors de l'exécution), ou 0 si le type de l'objet est incompatible.
Par exemple, admettons que ''MyWidget'', déclaré avec la macro [[QObject#Q_OBJECT|Q_OBJECT]], hérite de [[QWidget]] :
QObject *obj = new MyWidget;
La variable ''obj'', de type ''QObject *'', se réfère actuellement à un ''MyWidget'', donc peut être convertie convenablement :
QWidget *widget = qobject_cast(obj);
La conversion de [[QObject]] à [[QWidget]] est faite avec succès car l'objet est actuellement un ''MyWidget'', qui est une sous-classe de [[QWidget]]. Depuis que nous savons que ''obj'' est un ''MyWidget'', nous pouvons aussi le convertir en ''MyWidget *'' :
MyWidget *myWidget = qobject_cast(obj);
La conversion de type vers ''MyWidget'' est un succès car [[QObject#qobject_cast()]] ne fait pas de distinction entre les types inclus avec Qt et les types personnalisés.
QLabel *label = qobject_cast(obj);
// label est à 0
La conversion vers [[QLabel]], d'autre part, échoue. Le pointeur est alors défini à 0. Cela rend possible la gestion des objets de différents types lors de l'exécution basée sur le type :
if (QLabel *label = qobject_cast(obj)) {
label->setText(tr("Ping"));
} else if (QPushButton *button = qobject_cast(obj)) {
button->setText(tr("Pong!"));
}
Il est possible d'utiliser [[QObject]] en tant que classe de base sans la macro [[QObject#Q_OBJECT|Q_OBJECT]] ni le code de méta-objets, mais ni les signaux ni les slots ni tout autre dispositif décrit ici ne sera disponible si la macro n'est pas utilisée. Depuis le point de vue du système de méta-objets, une sous-classe de [[QObject]] sans code méta est l'équivalent de son ancêtre le plus proche qui possède un code de méta-objets. Cela signifie par exemple que [[QMetaObject#className|QMetaObject::className()]] ne retournera pas le nom actuel de votre classe mais celui de son ancêtre.
Par conséquent, nous recommandons fortement que toutes les sous-classes de [[QObject]] utilisent la macro [[QObject#Q_OBJECT|Q_OBJECT]] sans prêter attention au fait qu'elles utilisent ou non les signaux, les slots et les propriétés.
Voir aussi [[QMetaObject]], [[properties|Le système de propriétés de Qt]] et [[signalsandslots|Les signaux et les slots]].
==== Remerciements ====
Merci à pour la traduction ainsi qu'à et à pour leur relecture !