IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Appel automatique du constructeur par defaut ?


Sujet :

C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut Appel automatique du constructeur par defaut ?
    Salut,

    J'ai une classe B qui derive d'une classe A et qui possede 2 constructeurs. Le constructeur par defaut appelle le constructeur parent (celui de A) alors que l'autre constructeur n'appelle rien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A{
        A();
    };
     
    class B : public A{
        B();
        B(int i);
    };
     
    B::B() : A(){}
     
    B::B(int i){}
    Lorsque je fais J'ai l'impression que le constructeur de A est quand meme appele.

    Est-ce que ca vient du fais que le contructeur par defaut est toujours appele (et qu'il appelle lui meme le constructeur parent) ?
    Est-ce que ca vient du fais que le contructeur parent est toujours appele ?
    Est-ce que je fabule ?

    Merci de m'apporter vos lumieres

  2. #2
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Ca vient du fait qu'un constructeur de la classe parente est toujours appelé.
    Après, faut voir lequel tu veux appeler (ca peut être celui par défaut, comme un autre), ca ne dépend que de toi. Mais sache que par défaut, c'est le constructeur par défaut qui est appelé (logique non ? )

    PS: remplace ton constructeur par défaut pas un constructeur attendant un argument et ton code ne compile plus.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut
    Donc, la solution c'est de creer un constructeur A(int i) qui ne fait rien et de l'appeler explicitement ?

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    La solution, c'est tout d'abord de comprendre pourquoi tu voudrais qu'un objet de type B n'initialise pas sa sous partie de type A. Ca sent l'héritage qui n'aurait pas dû avoir lieu... Peut-être pourra-t-on mieux t'aider si tu nous explique ta problématique (et pas avec des noms comme A et B).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    La solution, c'est tout d'abord de comprendre pourquoi tu voudrais qu'un objet de type B n'initialise pas sa sous partie de type A. Ca sent l'héritage qui n'aurait pas dû avoir lieu... Peut-être pourra-t-on mieux t'aider si tu nous explique ta problématique (et pas avec des noms comme A et B).
    On dirait, oui.

    Tymk > est-ce que tout s'arrange si tu mets 'A' en attribut de B, via une instance statique, un pointeur vers A ou autre ?

  6. #6
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 898
    Points : 1 915
    Points
    1 915
    Par défaut
    Citation Envoyé par Tymk Voir le message
    J'ai l'impression que le constructeur de A est quand meme appele.
    Une classe mère sert de base, de fondation à une classe fille. Le constructeur d'une classe fille appelle toujours un constructeur de la classe mère (bien que tu puisses spécifier lequel). Sinon, ce serait comme vouloir faire le premier étage d'un immeuble mais pas le rez-de-chaussée !

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut
    Citation Envoyé par Noxen Voir le message
    Sinon, ce serait comme vouloir faire le premier étage d'un immeuble mais pas le rez-de-chaussée !
    En l'occurence, c'est exactement ce que je veux faire...

    Les classes SOCKET_TCP_CLIENT et SOCKET_TCP_SERVER derivent toutes les 2 de SOCKET_TCP.

    SOCKET_TCP appelle dans son constructeur par defaut la methode create_socket() qui cree un socket en mode TCP. En fonctionnement normal, les classes SOCKET_TCP_CLIENT et SOCKET_TCP_SERVER doivent donc appeler ce constructeur.

    Neanmoins, le SOCKET_TCP_SERVER appelle la fonction accept() qui cree un socket de type client. J'ai donc declare dans ma classe SOCKET_TCP_SERVER un pointeur vers une instance de SOCKET_TCP_CLIENT. Je recupere le descripteur de socket retroune par accept() et je definie cette instance par l'appel d'un constructeur SOCKET_TCP_CLIENT(int desc_sock).

    Le constructeur SOCKET_TCP_CLIENT(int desc_sock) ne doit surtout pas appeler le constructeur SOCKET_TCP(). Sinon, ce dernier cree un socket qui ne sert a rien puisque accept() a deja cree le socket client.

    Pour le moment, ce socket inutile est cree. Au regard de ces informations, est-ce que creer un constructeur A(int i) qui ne fait rien et l'appeler explicitement est une solution viable ?

    Citation Envoyé par Alp
    Tymk > est-ce que tout s'arrange si tu mets 'A' en attribut de B, via une instance statique, un pointeur vers A ou autre ?
    Arf, j'ai pas encore les accreditations suffisantes pour acceder a ce vocabulaire technique. Est-ce grave ?

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    J'ai l'impression après avoir fait une lecture rapide que ce dont tu as besoin, au niveau de la classe da base, c'est bien de 2 constructeur, mais le second ne serait pas un constructeur bidon, mais un constructeur qui prenne en paramètre une socket existante et la stocke comme étant sa socket.

    Une alternative pourrait être de dire que SOCKET_TCP ne crée jamais la socket dans son constructeur (c'est bien une classe abstraite ?) mais fournit juste à ses dérivées les points d'entrée pour le faire s'ils en ont besoin.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    J'ai l'impression après avoir fait une lecture rapide que ce dont tu as besoin, au niveau de la classe da base, c'est bien de 2 constructeur, mais le second ne serait pas un constructeur bidon, mais un constructeur qui prenne en paramètre une socket existante et la stocke comme étant sa socket.
    C'est deja ce que je fais au niveau de SOCKET_TCP_CLIENT.
    J'ai un constructeur par defaut qui appelle le constructeur parent et ce dernier cree le socket.
    J'ai un constructeur qui prend un descripteur de socket et qui l'affecte au descripteur de socket membre de la classe. (et qui normalement n'appelle pas le constructeur parent pour eviter la creation d'un socket en trop).

    Mais, il serai effectivement plus judicieux de definir le fonctionnement du constructeur SOCKET_TCP_CLIENT(int) dans un constructeur parent SOCKET_TCP(int). Meme si ce constructeur parent n'a aucun interet pour la classe SOCKET_TCP_SERVER qui en derive. C'est toujours mieux que de mettre un constructeur bidon.

    Citation Envoyé par JolyLoic Voir le message
    Une alternative pourrait être de dire que SOCKET_TCP ne crée jamais la socket dans son constructeur (c'est bien une classe abstraite ?) mais fournit juste à ses dérivées les points d'entrée pour le faire s'ils en ont besoin.
    SOCKET_TCP est une classe abstraite qui ne contient que la methode create_socket() (et d'autres fonctions virtuelles pures). Il est important que cette methode soit definie dans SOCKET_TCP car elle est commune aux 2 classes derivees SOCKET_TCP_CLIENT, SOCKET_TCP_SERVER.

    Edit : En plus, je trouve qu'une classe ne contenant que des methodes virtuelles pures n'a pas vraiment d'interet.

  10. #10
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 898
    Points : 1 915
    Points
    1 915
    Par défaut
    Citation Envoyé par Tymk Voir le message
    (et qui normalement n'appelle pas le constructeur parent pour eviter la creation d'un socket en trop).
    Si !! Même si tu ne définis pas de constructeur, le compilateur va générer un constructeur implicite. Même si ton constructeur "ne fait rien", il sera quand même appelé. Création d'objet = appel au constructeur (enfin, on ne parlera pas du placement new ici). Il faut vraiment comprendre que l'objet de la classe fille est créé "autour", ou "sur", de l'objet de la classe mère. D'ailleurs, par rapport au polymorphisme, le constructeur ne peut PAS être déclaré virtual, toute création d'objet passe par la création ascendante (classe mère vers classe fille) des composants de l'objet.

    Citation Envoyé par Tymk Voir le message
    C'est toujours mieux que de mettre un constructeur bidon.
    Rien ne t'empêche de créer un constructeur qui n'effectue aucun traitement. Il peut même être nécessaire de définir explicitement un constructeur non-paramétré (du moins, si ça a un sens), même s'il ne fait rien de spécial. Notamment, si tu définis un constructeur paramétré, mais pas de constructeur non-paramétré, le compilateur va considéré que cet objet DOIT être créé avec des paramètres (je suppose que ce doit être une histoire de masquage), tu ne peux plus créer d'objet de ta classe sans lui donner de paramètre. C'est important, parce-que par exemple tu ne pourras plus créer de tableau d'objet, puisque la création du tableau suppose la création d'objets, auxquels tu ne donnes pas de paramètres.

    Citation Envoyé par Tymk Voir le message
    Edit : En plus, je trouve qu'une classe ne contenant que des methodes virtuelles pures n'a pas vraiment d'interet.
    C'est ce qu'on appelle une interface. Une interface ne définit normalement pas de traitements. Son rôle est de présenter une liste de services, que devront implémenter toutes les classes qui sont sensées respecter cette interface.

    Par exemple : supposons que tu fasses une application qui gère des données, ces données devant ensuite être stockées dans un fichier xml, et donc respectant un formatage xml. Cela signifie que tout les objets qui seront transmis au, et manipulés par, le gestionnaire de données dans ton application devront être capable de fournir au gestionnaire une chaîne de caractères contenant ses données, formatées pour respecter un schéma xml ; peut importe comment ils créent cette chaîne, la seule chose qui compte est qu'ils la donnent au moment où on la leur demande.

    Tu vas créer une interface :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class ISerializable
    {
    public:
        virtual std::string ToXML() const = 0 ;
    };
    et tous les objets qui seront transmis devront hériter de cette interface et devront fournir une réponse à un appel à ToXML().

    Si quelque chose te semble ambigüe, n'hésite pas à demander

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 22/10/2011, 19h07
  2. Réponses: 12
    Dernier message: 13/10/2007, 11h37
  3. Classe membre sans constructeur par defaut
    Par TheDrev dans le forum C++
    Réponses: 6
    Dernier message: 28/09/2007, 12h13
  4. appeler le package par defaut
    Par al3alwa dans le forum Langage
    Réponses: 4
    Dernier message: 18/06/2007, 09h50
  5. probleme appel constructeur par default en extern
    Par Delgador dans le forum C++
    Réponses: 3
    Dernier message: 25/04/2007, 16h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo