Je ne comprends pas ce que pourraient être les problèmes si un constructeur était hérité d'une classe de base. Cpp Primer Plus dit:
Les constructeurs diffèrent des autres méthodes de classe en ce qu'ils créent de nouveaux objets, alors que d'autres méthodes sont appelées par des objets existants . C'est une des raisons pour lesquelles les constructeurs ne sont pas hérités . Héritage signifie qu'un objet dérivé peut utiliser une méthode de classe de base, mais que, dans le cas des constructeurs, l'objet n'existe pas avant que le constructeur ait effectué son travail.
Je comprends que le constructeur est appelé avant la construction de l’objet.
Comment cela peut-il engendrer des problèmes si une classe enfant hérite (le terme héritage signifie que la classe enfant peut redéfinir la méthode de la classe parent, etc. )
Je comprends qu’il n’est pas nécessaire d’appeler explicitement un constructeur à partir d’un code [même si je n’en ai pas encore conscience.] Sauf lors de la création d’objets. Même alors, vous pouvez le faire en utilisant un mécanisme pour appeler le constuctor parent [In cpp, en utilisant ::
ou en utilisant member initialiser list
, En java en utilisant super
]. En Java, il existe une application pour l'appeler dans la 1ère ligne. Je comprends que cela consiste à s'assurer que l'objet parent est créé en premier, puis que la construction de l'objet enfant se poursuit.
Cela peut l' emporter . Mais, je ne peux pas arriver à des situations où cela peut poser un problème. Si l'enfant hérite du constructeur parent, qu'est-ce qui peut mal tourner?
Donc, est-ce juste pour ne pas hériter des fonctions inutiles. Ou y a-t-il plus?
la source
Réponses:
Il ne peut y avoir d'héritage approprié des constructeurs en C ++, car le constructeur d'une classe dérivée doit effectuer des actions supplémentaires qu'un constructeur de classe de base n'a pas à faire et qu'il ignore. Ces actions supplémentaires sont l’initialisation des données membres de la classe dérivée (et dans une implémentation typique, définir également le vpointer pour faire référence aux classes dérivées vtable).
Quand une classe est construite, il y a toujours un certain nombre de choses qui doivent arriver: les constructeurs de la classe de base (le cas échéant) et les membres directs doivent être appelés et s'il y a des fonctions virtuelles, le vpointer doit être défini correctement . Si vous ne fournissez pas de constructeur pour votre classe, le compilateur en créera un qui effectuera les actions requises et rien d'autre. Si vous faites fournir un constructeur, mais manquer sur certaines des actions requises (par exemple, l'initialisation de certains membres), le compilateur ajoutera automatiquement les actions manquantes à votre constructeur. De cette manière, le compilateur s'assure que chaque classe a au moins un constructeur et que chaque constructeur initialise complètement les objets qu'il crée.
En C ++ 11, une forme d '"héritage de constructeur" a été introduite. Vous pouvez indiquer au compilateur de générer pour vous un ensemble de constructeurs prenant les mêmes arguments que les constructeurs de la classe de base et les transmettant simplement à la classe de base.
Bien qu'il s'appelle officiellement héritage, il ne l'est pas vraiment car il existe encore une fonction spécifique à la classe dérivée. Maintenant, il est simplement généré par le compilateur au lieu d’être écrit explicitement par vous.
Cette fonctionnalité fonctionne comme ceci:
Derived
a maintenant deux constructeurs (sans compter les constructeurs copier / déplacer). Celui qui prend un int et une chaîne et celui qui prend juste un int.la source
m()
vient, et comment cela changerait si son type était par exempleint
.using Base::Base
implicitement? Cela aurait de grandes conséquences si j'oubliais cette ligne sur une classe dérivée et que je devais hériter du constructeur de toutes les classes dérivéesCe que vous entendez par "hériter du constructeur parent" n'est pas clair. Vous utilisez le mot override , ce qui suggère que vous pensez peut-être aux constructeurs qui se comportent comme des fonctions virtuelles polymorphes . Je n'utilise délibérément pas le terme "constructeurs virtuels" car il s'agit d'un nom commun pour un modèle de code dans lequel vous avez en fait besoin d'une instance déjà existante d'un objet pour en créer un autre.
Les constructeurs polymorphes ne sont guère utiles en dehors du modèle "constructeur virtuel" et il est difficile de trouver un scénario concret dans lequel un constructeur polymorphe réel pourrait être utilisé. Un exemple très artificiel qui n'est en aucun cas même valide à distance en C ++ :
Dans ce cas, le constructeur appelé dépend du type concret de la variable en cours de construction ou d’attribution. Il est complexe à détecter lors de l’analyse / de la génération de code et n’a pas d’utilité: vous connaissez le type de béton que vous construisez et vous avez écrit un constructeur spécifique pour la classe dérivée. Le code C ++ valide suivant fait exactement la même chose, est légèrement plus court et est plus explicite:
Une deuxième interprétation, voire une question supplémentaire, est: que se passe-t-il si les constructeurs de la classe Base sont automatiquement présents dans toutes les classes dérivées, sauf s’ils sont explicitement masqués?
Vous devez écrire du code supplémentaire pour masquer un constructeur parent qu'il est incorrect d'utiliser lors de la construction de la classe dérivée. Cela peut arriver lorsque la classe dérivée spécialise la classe de base de manière à ce que certains paramètres deviennent non pertinents.
L'exemple typique est celui des rectangles et des carrés (notez que les carrés et les rectangles ne sont généralement pas substituables à Liskov, donc ce n'est pas un très bon dessin, mais cela met en évidence le problème).
Si Square hérite du constructeur à deux valeurs de Rectangle, vous pouvez construire des carrés de hauteur et de largeur différentes ... C'est logiquement faux, vous voulez donc masquer ce constructeur.
la source
Pourquoi les constructeurs ne sont-ils pas hérités: la réponse est étonnamment simple: le constructeur de la classe de base "construit" la classe de base et le constructeur de la classe héritée "construit" la classe héritée. Si la classe héritée hérite du constructeur, le constructeur essaiera de construire un objet de type classe de base et vous ne pourrez pas "construire" un objet de type classe héritée.
Quel genre de défaites le but d'hériter une classe.
la source
Le problème le plus évident en permettant à la classe dérivée de remplacer le constructeur de la classe de base est que le développeur de la classe dérivée est maintenant responsable de savoir comment construire sa / ses classe (s) de base. Que se passe-t-il lorsque la classe dérivée ne construit pas correctement la classe de base?
En outre, le principe de substitution de Liskov ne s'appliquerait plus car vous ne pouvez plus compter sur votre collection d'objets de classe de base compatibles, car rien ne garantit que la classe de base a été construite correctement ou de manière compatible avec les autres types dérivés.
Il est encore plus compliqué d'ajouter plus d'un niveau d'héritage. Maintenant, votre classe dérivée doit savoir comment construire toutes les classes de base en amont de la chaîne.
Que se passe-t-il ensuite si vous ajoutez une nouvelle classe de base en haut de la hiérarchie d'héritage? Vous devez mettre à jour tous les constructeurs de classe dérivés.
la source
Les constructeurs sont fondamentalement différents des autres méthodes:
Alors pourquoi ne sont-ils pas hérités? Réponse simple: Puisqu'il y a toujours un remplacement, généré ou écrit manuellement.
Pourquoi chaque classe a-t-elle besoin d'un constructeur? C'est une question compliquée et je pense que la réponse dépend du compilateur. Il existe un constructeur "trivial" pour lequel le compilateur n’exige pas qu’il soit appelé semble-t-il. Je pense que c’est la chose la plus proche de ce que vous entendez par héritage, mais pour les trois raisons énoncées ci-dessus, je pense que comparer les constructeurs aux méthodes normales n’est pas vraiment utile. :)
la source
Chaque classe a besoin d'un constructeur, même celui par défaut.
C ++ créera pour vous des constructeurs par défaut sauf si vous créez un constructeur spécialisé.
Si votre classe de base utilise un constructeur spécialisé, vous devez écrire le constructeur spécialisé sur la classe dérivée, même si les deux sont identiques, et les relier.
C ++ 11 vous permet d'éviter la duplication de code sur les constructeurs en utilisant :
Un ensemble de constructeurs hérités est composé de
Tous les constructeurs hérités qui ne sont pas le constructeur par défaut ou le constructeur copier / déplacer et dont les signatures ne correspondent pas aux constructeurs définis par l'utilisateur dans la classe dérivée, sont implicitement déclarés dans la classe dérivée. Les paramètres par défaut ne sont pas hérités
la source
Vous pouvez utiliser:
Vous demandez pourquoi vous devez faire cela?
La sous-classe peut avoir des propriétés supplémentaires qu'il peut être nécessaire d'initialiser dans le constructeur ou elle peut initialiser les variables de la classe de base d'une manière différente.
Sinon, comment créeriez-vous l'objet de sous-type?
la source