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++Builder Discussion :

Méthodes Virtuelles appelés depuis un Constructeur [Langage/Algorithme]


Sujet :

C++Builder

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 081
    Par défaut Méthodes Virtuelles appelés depuis un Constructeur
    Avant de lire ce sujet, veillez à lire et relire la FAQ :
    Puis-je appeler des fonctions virtuelles dans le constructeur (ou le destructeur) ?
    Puis la Doc Embarcadero (qui dit le contraire pour la VCL) :
    Appels de méthodes virtuelles dans les constructeurs des classes de base

    Il faudrait notifer dans la FAQ d'une telle différence de comportement, je suis développeur Delphi, je m'attendais au comportement des objets VCL alors que partout sur les sites C++, c'est évidemment le comportement C++ que les développeurs s'attendent !
    J'ai donc ou des sérieux doutes sur certains de mes codes que je n'aurais pas du avoir !

    Si l'on trouve rapidement cet article dans l'aide C++ Builder 6, c'est un défi de la trouver en BSD2007 !

    Un petit code pour illustrer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    //---------------------------------------------------------------------------
    #include <typeinfo>
    //---------------------------------------------------------------------------
    class CClassOne
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {OutputDebugString(typeid(this).name()); OutputDebugString("One");}
     
      public:
        /*constructor*/ CClassOne() {VirtualMethodInConstructor();}
    };
    //---------------------------------------------------------------------------
    class CClassTwo : public CClassOne
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {CClassOne::VirtualMethodInConstructor(); OutputDebugString("Two");}
     
      public:
        /*constructor*/ CClassTwo() {}
    };
    //---------------------------------------------------------------------------
    class CClassThree : public CClassTwo
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {CClassTwo::VirtualMethodInConstructor(); OutputDebugString("Three");}
     
      public:
        /*constructor*/ CClassThree() {}
    };
     
    //---------------------------------------------------------------------------
    class TClassOne : public TObject
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {OutputDebugString(typeid(this).name()); OutputDebugString(String(this->ClassName()).c_str()); OutputDebugString("VCL One");}
     
      public:
        /*constructor*/ TClassOne() {VirtualMethodInConstructor();}
    };
    //---------------------------------------------------------------------------
    class TClassTwo : public TClassOne
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {TClassOne::VirtualMethodInConstructor(); OutputDebugString("VCL Two");}
     
      public:
        /*constructor*/ TClassTwo() {}
    };
    //---------------------------------------------------------------------------
    class TClassThree : public TClassTwo
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {TClassTwo::VirtualMethodInConstructor(); OutputDebugString("VCL Three");}
     
      public:
        /*constructor*/ TClassThree() {}
    };
     
     
    void __fastcall TLanguageBasicsForm::BtnConstructorAndVirtualMethodClick(
          TObject *Sender)
    {
      OutputDebugString("! - new CClassOne : ");
      CClassOne *OneC = new CClassOne(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassTwo : ");
      CClassOne *TwoC = new CClassTwo(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassThree : ");
      CClassOne *ThreeC = new CClassThree(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassTwo : ");
      CClassTwo *TwoC2 = new CClassTwo(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassThree : ");
      CClassTwo *ThreeC2 = new CClassThree(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassThree : ");
      CClassThree *ThreeC3 = new CClassThree(); // Affiche CClassOne One
     
     
      delete OneC;
      delete TwoC;
      delete ThreeC;
      delete TwoC2;
      delete ThreeC2;
      delete ThreeC3;
     
      OutputDebugString("! - VCL new CClassOne : ");
      TClassOne *OneVCL = new TClassOne(); // Affiche TClassOne TClassOne VCL One
     
      OutputDebugString("! - VCL new TClassTwo : ");
      TClassOne *TwoVCL = new TClassTwo(); // Affiche TClassOne TClassTwo VCL One VCL Two
     
      OutputDebugString("! - VCL new TClassThree : ");
      TClassOne *ThreeVCL = new TClassThree(); // Affiche TClassOne TClassThree VCL One VCL Two VCL Three
     
      OutputDebugString("! - VCL new TClassTwo : ");
      TClassTwo *TwoVCL2 = new TClassTwo(); // Affiche TClassOne TClassTwo VCL One VCL Two
     
      OutputDebugString("! - VCL new TClassThree : ");
      TClassTwo *ThreeVCL2 = new TClassThree(); // Affiche TClassOne TClassThree VCL One VCL Two VCL Three
     
      OutputDebugString("! - VCL new TClassThree : ");
      TClassThree *ThreeVCL3 = new TClassThree(); // Affiche TClassOne TClassThree VCL One VCL Two VCL Three
     
      delete OneVCL;
      delete TwoVCL;
      delete ThreeVCL;
      delete TwoVCL2;
      delete ThreeVCL2;
      delete ThreeVCL3;
    }
    //---------------------------------------------------------------------------
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut
    C'est en lisant ce poste que je me rends compte à quel point je suis à la rue. Je n'ai malheureusement pas le temps d'approfondir toutes ces notions.

    L'avantage par contre est de m'avoir fait lire un peu de la FAQ C++ qui m'a apportée beaucoup de réponses!

  3. #3
    Membre expérimenté

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par défaut
    Rassure-toi moi également.
    En fait je ne suis pas tant choqué que ça par la différence de comportement (très étonnant en effet - merci ShaiLeTroll) que par le code suivant:
    Dans quel cas peut-on avoir besoin d'écrire ça ? Pour l'instant c'est ça qui m'interpelle le plus
    B* b = new B(); avec downcast ou upcast, ça ok. Mais le code ci-dessus je ne vois pas de situation ou j'aurais eu besoin (et encore moins envie) d'écrire ça - je ne savais même pas qu'on pouvait le faire.

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Citation Envoyé par ShaiLeTroll Voir le message
    Il faudrait notifer dans la FAQ d'une telle différence de comportement
    C'est une F.A.Q C++ pas BCB. Donc c'est normal que ce ne soit pas mentionné puisque Borland a choisi d'avoir des comportements spécifiques. Préciser les comportements particuliers de chaque framework/compilateur dans la F.A.Q C++ deviendrait vite fastidieux et introduirait probablement de la confusion chez les développeurs C++.

    Ceci dit, ça pourrait effectivement faire partie d'une entrée dédiée dans la FAQ C++ Builder

    Citation Envoyé par yarp Voir le message
    C'est assez classique quand B hérite de A et que l'on souhaite uniquement avoir un pointeur sur la classe de base.

    Autre chose qui m'a surpris dans l'exemple du lien embarcadero proposé par shailLeTroll :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class  Base :  public  TObject { 
    
    public : 
    __fastcall  Base() { init();  } 
    virtual void __fastcall  init() {  } 
    
    }; 
    
    class  Derived :  public  Base { 
    
    public : 
    Derived( int  nz) : not_zero(nz) {  } 
    virtual void __fastcall  init( ) 
    { 
    
    if  (not_zero == 0 )  // ?????????
    throw  Exception("not_zero is zero!") ; 
    } 
    private : 
    int  not_zero ; 
    } ;
    En C++, la variable ne vaut pas 0 mais n'importe quoi tant qu'elle n'a pas été intialisée

  5. #5
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 081
    Par défaut
    Oui, je parlais bien d'ajout dans la FAQ C++ Builder !
    Rien que pour cet information ait plus de visibilité !

    Pour les Zéros, voir mon sujet Initialisation à Zéro d'Objet C++, je dirais que c'est même l'une des 1ere chose que j'ai testé !
    Etant programmeur Delphi, c'est le fait qu'un objet C++ Strict ne le fasse pas !
    Du coup, je dérive tout du TObject, rien que parce que j'utilise bcp de TObjectList, les RTTI et que mon code est clairement orienté VCL (quelques exceptions pour vector<int> ou map<String, String>)

    Citation Envoyé par yarp Voir le message
    Dans quel cas peut-on avoir besoin d'écrire ça ? Pour l'instant c'est ça qui m'interpelle le plus
    B* b = new B(); avec downcast ou upcast, ça ok. Mais le code ci-dessus je ne vois pas de situation ou j'aurais eu besoin (et encore moins envie) d'écrire ça - je ne savais même pas qu'on pouvait le faire.
    Ce qui me choque c'est que cela t'interpelle, regarde la TActionList, par défaut, l'item est un TContainedAction avec une instanciation des items par TAction pour les actions génériques, mais il y a des actions prédéfinies comme TWindowClose, TWindowCascade, TFileOpen... c'est un des fondements de la programmation objet : le Polymorphisme !
    Cela se retrouve souvent avec un tableau d'objet comme "Forme[] tableau" de Wikipedia ou avec TObjectList\TCollection

    [MODE TROLL ON]si tu es un professionnel, Change de métier [MODE TROLL OFF]
    si tu es un amateur, voilà une grande découverte pour toi !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre très actif Avatar de nirgal76
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2007
    Messages
    923
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 923
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    C'est une F.A.Q C++ pas BCB. Donc c'est normal que ce ne soit pas mentionné puisque Borland a choisi d'avoir des comportements spécifiques. Préciser les comportements particuliers de chaque framework/compilateur dans la F.A.Q C++ deviendrait vite fastidieux et introduirait probablement de la confusion chez les développeurs C++.

    Ceci dit, ça pourrait effectivement faire partie d'une entrée dédiée dans la FAQ C++ Builder

    C'est assez classique quand B hérite de A et que l'on souhaite uniquement avoir un pointeur sur la classe de base.

    Autre chose qui m'a surpris dans l'exemple du lien embarcadero proposé par shailLeTroll :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class  Base :  public  TObject { 
    
    public : 
    __fastcall  Base() { init();  } 
    virtual void __fastcall  init() {  } 
    
    }; 
    
    class  Derived :  public  Base { 
    
    public : 
    Derived( int  nz) : not_zero(nz) {  } 
    virtual void __fastcall  init( ) 
    { 
    
    if  (not_zero == 0 )  // ?????????
    throw  Exception("not_zero is zero!") ; 
    } 
    private : 
    int  not_zero ; 
    } ;
    En C++, la variable ne vaut pas 0 mais n'importe quoi tant qu'elle n'a pas été intialisée
    Oui mais la mémoire des classes vcl est initialisé à zéro. Pour des variables membres comme not_zero, ça signifie que sa valeur sera 0 à l'initialisation. Ce qui n'est pas valable en C++ standard ou sa valeur sera effectivement indéterminée.
    Donc danger, ça fait prendre de mauvaises habitudes et peut rendre le portage du code vers d'autres C++ très aléatoire en terme de stabilité.
    Et d'une manière général, j'évite tout code qui peut déclencher une exception dans un constructeur. J'appelle la fonction Init() après construction dont le rôle se limite à construire l'objet.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par nirgal76 Voir le message
    Oui mais la mémoire des classes vcl est initialisé à zéro. Pour des variables membres comme not_zero, ça signifie que sa valeur sera 0 à l'initialisation. Ce qui n'est pas valable en C++ standard ou sa valeur sera effectivement indéterminée.
    Donc danger, ça fait prendre de mauvaises habitudes et peut rendre le portage du code vers d'autres C++ très aléatoire en terme de stabilité.
    J'aurais tendance à faire comme toi, privilégier les codes portables, mais je ne sais pas quels sont les habitudes des projets BCB.
    Citation Envoyé par nirgal76 Voir le message
    Et d'une manière général, j'évite tout code qui peut déclencher une exception dans un constructeur. J'appelle la fonction Init() après construction dont le rôle se limite à construire l'objet.
    Ben, là je ne suis pas d'accord en C++ standard. Le constructeur est fait pour produire un objet directement utilisable (i.e. tous les invariants ont été construits/mis en place). S'il ne peut pas, alors génération d'une exception. Le langage sait quels destructeurs appeler ou pas dans ce cas. Séparer en constructeur + fonction ini c'est perdre l'intérêt du constructeur + celui des exceptions en refusant de les lancer dans le constructeur. Les exceptions dans les constructeurs, c'est sans risque si on a bien fait attention à gérer ses ressources avec des enveloppes RAII. L'utilisation de constructeur + ini c'est l'assurance d'avoir un jour ou l'autre une situation où on 'oublie' d'appeler la fonction d'ini. Et là, en général boum

    Là où on ne lance pas d'exception, c'est dans un destructeur. Ca a peu de sens de dire qu'une destruction échoue. Ca peut même être assez problématique dans certains cas.

    Cf F.A.Q (C++) :
    Peut-on lever des exceptions dans les constructeurs ?
    Peut-on lever des exceptions dans les destructeurs ?

  8. #8
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 081
    Par défaut
    En fait, en C++, il y a une initialisation des objets statiques !
    Il ne faut pas l'oublier, des objets tel que vector ou String !

    le seul moyen pour interrompre une construction, c'est une exception, en Delphi, il faut savoir que si une exception se produit durant le constructeur, cela appelle le destructeur (d'où l'utilité de l'initialisation à zéro pour tester nil\null)
    En C++, faudra que je teste, ce comportement, il me semble qu'il faut soit même gérer les libérations en cas d'exception durant le constructeur !
    Encore une fois les différences C++ et VCL à ce sujet : Destruction d'objets qu'il faut comparer à la FAQ Peut-on lever des exceptions dans les constructeurs ?

    Il suffit de faire deux méthodes InternalCreate et InternalDestroy, le destroy étant capable de libérer un objet complètement ou partiellement construit !

    Pour le portage vers d'autres C++, cela me fait toujours sourire quand l'on utilise C++ Builder et de vouloir faire un code compatible et portable !
    Trop de directive, de mot clé, ... mieux vaut écrire un C++ avec gcc, puis de l'utiliser en BCB, mais faire l'inverse, ça semble pénible de se limiter au C++ strict (tout simplement parce que l'IDE n'est pas conçu pour cela, on peut s'en sortir en faisant une DLL en désactivant le support VCL)

    En plus, mieux vaut éviter, plus il y a de besoins pour écrire un code C++ spécifique à chaque environnement, plus cela fait d'emploi !
    Les grosses sociétés ne se posent pas la question : "faisons un code portable", lorsqu'il y a déjà 30 développeurs Delphi, 40 développeur .NET, 20 intégrateurs SAP, embauche 10 de plus via des SSII pour faire du VSC++ et 10 autres pour du C++Builder, ils embauchent puis jette le développeur comme vieille chaussette trouée ! Je connais au moins 4 développeur qui ont vécu cela !

    Tu appeles Init après le constructeur ! en dehors !
    J'espère que le code est bien documenté pour que les autres développeurs qui travaille avec tes objets ne l'oublie pas !

    J'en reviens sur les méthodes virtuelles appelées depuis un constructeur qui contourne en VCL, la sécurité naturelle du C++
    Pourquoi cette règle ? Une fonction définie dans C a accès aux données membre de C. Or, on a vu que au moment où on exécute l'appel au corps du constructeur de B, ces dernières ne sont pas encore créées. On a donc préféré jouer la sécurité.
    Ce qui suit est assez hallucinant aussi, j'ai commencé le développement d'une couche Objet Métier générique qui utilise les RTTI pour s'alimenter à partir d'une DB
    L'initialisation des objets C++ par "itération" peut provoquer ce genre d'anomalie si l'on joue avec les méthodes virtuelles depuis un ancêtre ce que fait la TForm en lisant la DFM, vous remarquerez que les membres publiés d'une TForm soit des Pointeurs sur Objet qui ne sont pas initialisé par les mécanismes C++ ou des property (qui ne sont pas affecté non plus)

    Du coup, j'utilise des String* avec des accesseurs pour contourner l'initialisation automatique des objets statiques par "itération" du C++

    Vous noterez pour TClassTwo
    que l'on pert Two et mais pas 2 lors de l'initialisation de TClassTwo

    Vous noterez pour TClassThree
    que l'on pert Two et mais pas 2 ni Three, ni 3 lors de l'initialisation de TClassTwo
    que l'on fini par perdre Three mais ni 2 ni 3 lors de l'initialisation de TClassThree


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    //---------------------------------------------------------------------------
    #include <typeinfo>
    //---------------------------------------------------------------------------
    class CClassOne
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {OutputDebugString(typeid(this).name()); OutputDebugString("One");}
     
      public:
        /*constructor*/ CClassOne() {VirtualMethodInConstructor();}
    };
    //---------------------------------------------------------------------------
    class CClassTwo : public CClassOne
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {CClassOne::VirtualMethodInConstructor(); OutputDebugString("Two");}
     
      public:
        /*constructor*/ CClassTwo() {}
    };
    //---------------------------------------------------------------------------
    class CClassThree : public CClassTwo
    {
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {CClassTwo::VirtualMethodInConstructor(); OutputDebugString("Three");}
     
      public:
        /*constructor*/ CClassThree() {}
    };
     
    //---------------------------------------------------------------------------
    class TClassOne : public TObject
    {
      private:
        // Membres Privés
        int FValueOne;
        String FTextOne;
     
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {OutputDebugString(typeid(this).name()); OutputDebugString(String(this->ClassName()).c_str()); OutputDebugString("VCL One");}
     
      public:
        /*constructor*/ TClassOne();
     
      __published:
        // Propriétés Publiées
        __property int ValueOne = {read=FValueOne, write=FValueOne};
        __property String TextOne = {read=FTextOne, write=FTextOne};
    };
    //---------------------------------------------------------------------------
    TClassOne:: TClassOne()
    {
      VirtualMethodInConstructor();
     
      if (IsPublishedProp(this, "ValueOne")) SetOrdProp(this, "ValueOne", 1);
      if (IsPublishedProp(this, "ValueTwo")) SetOrdProp(this, "ValueTwo", 2);
      if (IsPublishedProp(this, "ValueThree")) SetOrdProp(this, "ValueThree", 3);
      if (IsPublishedProp(this, "TextOne")) SetStrProp(this, "TextOne", "One");
      if (IsPublishedProp(this, "TextTwo")) SetStrProp(this, "TextTwo", "Two");
      if (IsPublishedProp(this, "TextThree")) SetStrProp(this, "TextThree", "Three");
      String ODSText = "Published One : ";
      if (IsPublishedProp(this, "ValueOne")) ODSText += "ValueOne : \"" + IntToStr(GetOrdProp(this, "ValueOne")) + "\" - ";
      if (IsPublishedProp(this, "ValueTwo")) ODSText += "ValueTwo : \"" + IntToStr(GetOrdProp(this, "ValueTwo")) + "\" - ";
      if (IsPublishedProp(this, "ValueThree")) ODSText += "ValueThree : \"" + IntToStr(GetOrdProp(this, "ValueThree")) + "\" - ";
      if (IsPublishedProp(this, "TextOne")) ODSText += "TextOne : \"" + GetStrProp(this, "TextOne") + "\" - ";
      if (IsPublishedProp(this, "TextTwo")) ODSText += "TextTwo : \"" + GetStrProp(this, "TextTwo") + "\" - ";
      if (IsPublishedProp(this, "TextThree")) ODSText += "TextThree : \"" + GetStrProp(this, "TextThree") + "\" - ";
      OutputDebugString(ODSText.c_str());
    }
     
    //---------------------------------------------------------------------------
    class TClassTwo : public TClassOne
    {
      private:
        // Membres Privés
        int FValueTwo;
        String FTextTwo;
     
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {TClassOne::VirtualMethodInConstructor(); OutputDebugString("VCL Two");}
     
      public:
        /*constructor*/ TClassTwo();
     
      __published:
        // Propriétés Publiées
        __property int ValueTwo = {read=FValueTwo, write=FValueTwo};
        __property String TextTwo = {read=FTextTwo, write=FTextTwo};
    };
    //---------------------------------------------------------------------------
    TClassTwo:: TClassTwo()
    {
      String ODSText = "Published Two : ";
      if (IsPublishedProp(this, "ValueOne")) ODSText += "ValueOne : \"" + IntToStr(GetOrdProp(this, "ValueOne")) + "\" - ";
      if (IsPublishedProp(this, "ValueTwo")) ODSText += "ValueTwo : \"" + IntToStr(GetOrdProp(this, "ValueTwo")) + "\" - ";
      if (IsPublishedProp(this, "ValueThree")) ODSText += "ValueThree : \"" + IntToStr(GetOrdProp(this, "ValueThree")) + "\" - ";
      if (IsPublishedProp(this, "TextOne")) ODSText += "TextOne : \"" + GetStrProp(this, "TextOne") + "\" - ";
      if (IsPublishedProp(this, "TextTwo")) ODSText += "TextTwo : \"" + GetStrProp(this, "TextTwo") + "\" - ";
      if (IsPublishedProp(this, "TextThree")) ODSText += "TextThree : \"" + GetStrProp(this, "TextThree") + "\" - ";
      OutputDebugString(ODSText.c_str());
    }
    //---------------------------------------------------------------------------
    class TClassThree : public TClassTwo
    {
      private:
        // Membres Privés
        int FValueThree;
        String FTextThree;
     
      protected:
        // Methodes Protégées
        virtual void VirtualMethodInConstructor() {TClassTwo::VirtualMethodInConstructor(); OutputDebugString("VCL Three");}
     
      public:
        /*constructor*/ TClassThree();
     
      __published:
        // Propriétés Publiées
        __property int ValueThree = {read=FValueThree, write=FValueThree};
        __property String TextThree = {read=FTextThree, write=FTextThree};
    };
    //---------------------------------------------------------------------------
    TClassThree:: TClassThree()
    {
      String ODSText = "Published Three : ";
      if (IsPublishedProp(this, "ValueOne")) ODSText += "ValueOne : \"" + IntToStr(GetOrdProp(this, "ValueOne")) + "\" - ";
      if (IsPublishedProp(this, "ValueTwo")) ODSText += "ValueTwo : \"" + IntToStr(GetOrdProp(this, "ValueTwo")) + "\" - ";
      if (IsPublishedProp(this, "ValueThree")) ODSText += "ValueThree : \"" + IntToStr(GetOrdProp(this, "ValueThree")) + "\" - ";
      if (IsPublishedProp(this, "TextOne")) ODSText += "TextOne : \"" + GetStrProp(this, "TextOne") + "\" - ";
      if (IsPublishedProp(this, "TextTwo")) ODSText += "TextTwo : \"" + GetStrProp(this, "TextTwo") + "\" - ";
      if (IsPublishedProp(this, "TextThree")) ODSText += "TextThree : \"" + GetStrProp(this, "TextThree") + "\" - ";
      OutputDebugString(ODSText.c_str());
    }
     
     
    void __fastcall TLanguageBasicsForm::BtnConstructorAndVirtualMethodClick(
          TObject *Sender)
    {
      OutputDebugString("! - new CClassOne : ");
      CClassOne *OneC = new CClassOne(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassTwo : ");
      CClassOne *TwoC = new CClassTwo(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassThree : ");
      CClassOne *ThreeC = new CClassThree(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassTwo : ");
      CClassTwo *TwoC2 = new CClassTwo(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassThree : ");
      CClassTwo *ThreeC2 = new CClassThree(); // Affiche CClassOne One
     
      OutputDebugString("! - new CClassThree : ");
      CClassThree *ThreeC3 = new CClassThree(); // Affiche CClassOne One
     
     
      delete OneC;
      delete TwoC;
      delete ThreeC;
      delete TwoC2;
      delete ThreeC2;
      delete ThreeC3;
     
      OutputDebugString("! - VCL new CClassOne : ");
      TClassOne *OneVCL = new TClassOne(); // Affiche TClassOne TClassOne VCL One
     
      OutputDebugString("! - VCL new TClassTwo : ");
      TClassOne *TwoVCL = new TClassTwo(); // Affiche TClassOne TClassTwo VCL One VCL Two
     
      OutputDebugString("! - VCL new TClassThree : ");
      TClassOne *ThreeVCL = new TClassThree(); // Affiche TClassOne TClassThree VCL One VCL Two VCL Three
     
      OutputDebugString("! - VCL new TClassTwo : ");
      TClassTwo *TwoVCL2 = new TClassTwo(); // Affiche TClassOne TClassTwo VCL One VCL Two
     
      OutputDebugString("! - VCL new TClassThree : ");
      TClassTwo *ThreeVCL2 = new TClassThree(); // Affiche TClassOne TClassThree VCL One VCL Two VCL Three
     
      OutputDebugString("! - VCL new TClassThree : ");
      TClassThree *ThreeVCL3 = new TClassThree(); // Affiche TClassOne TClassThree VCL One VCL Two VCL Three
     
      delete OneVCL;
      delete TwoVCL;
      delete ThreeVCL;
      delete TwoVCL2;
      delete ThreeVCL2;
      delete ThreeVCL3;
    }
    //---------------------------------------------------------------------------
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

Discussions similaires

  1. [PHP 5.3] Savoir quelle méthode est appelée via le constructeur
    Par Madfrix dans le forum Langage
    Réponses: 14
    Dernier message: 19/10/2010, 16h45
  2. Réponses: 6
    Dernier message: 10/10/2007, 20h11
  3. Réponses: 15
    Dernier message: 05/07/2007, 01h29
  4. Appel d'une méthode virtuelles
    Par BIPBIP59 dans le forum C++Builder
    Réponses: 4
    Dernier message: 24/03/2006, 14h00
  5. Comment l'appel à une méthode virtuelle....
    Par Blobette dans le forum C++
    Réponses: 7
    Dernier message: 07/12/2004, 13h55

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