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

Langage C++ Discussion :

Héritage, destructeurs et performances


Sujet :

Langage C++

  1. #41
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    je pensais surtout à des choses comme GMP (ou what ever else ) qui peuvent être nécessaires pour représenter un nombre dans certains cas (surtout quand les type natif du C++ ne sont plus suffisants).
    Si tu as une expérience sur GMP, ça m'intéresse!
    Est-ce que tu as évalué la perte de performance quand on diminue/augmente la précision des calculs?
    Est-ce que tu as repéré des astuces de programmation intéressantes dedans (idioms/patterns)?

    Au sujet de la confiance, l'utilisation de la classe template impose un "contrat" au paramètre template en terme de fonctionnalités, je ne vois pas de problèmes potentiels.
    J'ai l'impression que c'est le contraire mais peut-être à tort (ce qui m'arrangerait bien ).
    Quand tu parles de contrat, tu veux parler du fait que les opérateurs +,-,*,/ doivent être surchargés pour le typename T?

    Bah disons que certains compilateurs sont plus compatible que d'autres et qu'il a fallu 11 ans au C99 pour arriver là. Le C99 a plutôt mal percé dans la communauté C.
    Ah oui quand même, il n'y a que Sun Studio!

    En l'état actuel (le code du 1er post, je ne crois qu'il ait évolué en parcourant en diagonale les posts), tu as des héritages vide de sens car il n'apportent rien. Une approche transversale (à bas de template "seule") serait sans doute mieux. Mais de toute façon, je ne vois même pas à quoi peut te servir ces classes puisqu'elles n'ont aucune "valeur ajoutée", elles sont aussi vides de sens. Bref, je ne vois pas quoi ca pourrait te servir ou pourquoi tu fais ca.
    J'ai un peu ce sentiment aussi mais je n'ai pas trouvé mieux.
    La raison première : fermer l'utilisation de mes templates aux types que je souhaite.
    Mais apparemment tu dis que ça ne sert à rien.
    Deuxième raison : initialiser à zéro par défaut mes nombres.
    Il y a sûrement une option de compilation qui permet de faire ça mais je ne peux pas gérer tous les compilateurs.
    Troisième raison : stocker des nombres de types différents dans un même tableau.
    Contrainte : aucune perte de performance par rapport aux opérations sur les types standards (int,float,...).

    Dans mon projet, je souhaite aussi faire un peu de calcul symbolique (sur des polynômes/fonctions rationnelles) et faire de la précision mixte (un peu dans l'esprit de GMP) mais je n'y ai pas encore réfléchi pour le moment.
    Disons que pour ça, avoir une classe représentant tous les nombres me paraît une bonne idée à première vue.

  2. #42
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    La raison première : fermer l'utilisation de mes templates aux types que je souhaite.
    Mais apparemment tu dis que ça ne sert à rien.
    Pourquoi vouloir le faire

    Ce n'est pas à toi de placer des restrictions qui n'ont pas forcément lieu d'être à l'utilisation de ce que tu donnes à quelqu'un d'autre:

    Ton but et de fournir quelque chose qui fonctionne, dans des situations clairement identifiées, mais:
    Peut être as-tu oublié une situation qui serait pourtant... indispensable à l'utilisateur de ton code

    • Tu ne peux être tenu responsable que de ce que tu fais toi même: combien d'invention sont la meilleure et la pire des choses faut-il forcément juger leur inventeur si, par malheur, d'autres les utilisent à mauvais escient
    Et puis, il est possible, avec les template, de limiter l'utilisation de classes à des type particulier, grâce à la spécialisation partielle / totale:
    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
    template <typename T>
    class Class;
    /* fonctionnera pour les float */>
    template <>
    class Class<float>
    {
        /* ...*/
    };
    /* et pour les double */
    template <>
    class Class<double>
    {
        /*...*/
    };
    /* tout autre type résultera en une erreur de compilation */
    voir de veiller à la présence d'un certain concept dans le type utilisé

    Et puis: qu'est-ce qui empêcherait l'utilisateur de ton code de faire hériter d'une des classes se trouvant plus haut dans ta hiérarchie de classes (ou d'ajouter une spécialisation que tu n'a pas prévu à la base)
    Deuxième raison : initialiser à zéro par défaut mes nombres.
    Il y a sûrement une option de compilation qui permet de faire ça mais je ne peux pas gérer tous les compilateurs.
    Est-ce utile

    N'est il pas plus intéressant de forcer l'utilisateur à créer son objet une fois qu'il a calculé sa valeur de départ

    Je ne tranche pas la question ici, je ne fais que la poser
    Troisième raison : stocker des nombres de types différents dans un même tableau.
    Interroge toi peut être sur la raison pour laquelle tu voudrais pouvoir le faire...

    La raison évidente pour des types ayant sémantique de valeur serait de pouvoir...les stocker de manière à effectuer certaines opérations (mathématiques ici) sur les différents éléments du tableau.

    Le problème réside dans le fait que les différents types primitifs qui pourraient être utilisés pour spécialiser ta classe présentent des plages de valeurs et des précisions différentes.
    1. Que se passerait il si l'utilisateur (ou toi) stockait des objets basés sur des plages et des précisions différentes
    2. Accepterais tu d'être limité à la plage de valeur et à la précision autorisée par le type primitif qui présente les plus petites
    3. Comment gérer la perte de précision ou de plage de valeur que cela impliquerait

    Contrainte : aucune perte de performance par rapport aux opérations sur les types standards (int,float,...).
    Le fait est que, si tu veux pouvoir placer dans une collection des objet qui "passent pour être d'un type de base", tu travailles avec des objets ayant sémantique d'entité, et non avec des objet ayant sémantique de valeur.

    A partir du moment où tu veux profiter du polymorphisme, tu sera confronté au passage par la vtable.

    Cela ne prend "pas énormément" de temps, mais cela en prend toujours plus que de ne pas faire le détour
    Dans mon projet, je souhaite aussi faire un peu de calcul symbolique (sur des polynômes/fonctions rationnelles) et faire de la précision mixte (un peu dans l'esprit de GMP) mais je n'y ai pas encore réfléchi pour le moment.

    Disons que pour ça, avoir une classe représentant tous les nombres me paraît une bonne idée à première vue.
    Je ne crois pas...

    Car tes nombres ne seront jamais que des valeurs, et, lorsque tu travaillera avec un type de valeur donné, ce sera parce que tu as estimé que le type en question fournit une plage de valeurs et une précision suffisante.

    Tu ne vas donc pas mélanger les différents types de valeurs, parce que cela reviendrait à mélanger... les pommes et les poires
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #43
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    La raison première : fermer l'utilisation de mes templates aux types que je souhaite.
    Documente le/les concept(s) que doivent respecter les types et laisse l'utilisateur se tiré une balle dans le pied si il n'est pas capable de lire de la doc.
    (Ou alors SFINAE pour vérifier l'interface présenté, ou la BCCL)
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  4. #44
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    Citation Envoyé par koala01 Voir le message
    Et puis, il est possible, avec les template, de limiter l'utilisation de classes à des type particulier, grâce à la spécialisation partielle / totale
    Je ne partage pas nécessairement ce qui a précédé cette phrase mais j'adhère totalement à la solution technique proposée!

    Citation Envoyé par koala01 Voir le message
    Et puis: qu'est-ce qui empêcherait l'utilisateur de ton code de faire hériter d'une des classes se trouvant plus haut dans ta hiérarchie de classes (ou d'ajouter une spécialisation que tu n'a pas prévu à la base)
    Concernant la hiérarchisation ce n'est plus mon problème : je ne m'occupe que de l'existant.
    Pour la spécialisation, je pars du principe qu'il ne faut pas modifier l'encapsulation existante (constructeurs protégés ou classes abstraites).
    Mais je suis d'accord c'est techniquement possible.

    Citation Envoyé par koala01 Voir le message
    N'est il pas plus intéressant de forcer l'utilisateur à créer son objet une fois qu'il a calculé sa valeur de départ
    Je ne tranche pas la question ici, je ne fais que la poser
    J'espère que tu n'attends pas une réponse de ma part : je n'ai pas compris...

    Citation Envoyé par koala01 Voir le message
    La raison évidente pour des types ayant sémantique de valeur serait de pouvoir...les stocker de manière à effectuer certaines opérations (mathématiques ici) sur les différents éléments du tableau.
    La raison pratique c'est de pouvoir stocker des tableaux de données quantitatives (numériques), qualitatives et nominales pour faire de l'apprentissage statistique (les trois types de données pouvant bien sûr coexister dans un même tableau).
    A ce stade, les opérations à effectuer ne sont ni plus ni moins celles d'un bête tableur.
    Après, il y a effectivement un prétraitement de données et je me retrouve avec des données numériques uniquement (le cas que tu envisages).
    Les tableaux sont volumineux et j'y accède souvent : je ne peux pas me permettre de stocker en ram la copie "mixte" et la copie "numérique".

    Je suis entièrement d'accord avec toi pour les questions de précision numérique mais dans ce cas particulier je ne suis pas concerné.

    A partir du moment où tu veux profiter du polymorphisme, tu sera confronté au passage par la vtable.

    Cela ne prend "pas énormément" de temps, mais cela en prend toujours plus que de ne pas faire le détour
    De ce que j'ai pu constater, cela ne prend pas du tout de temps tant que je n'ai pas de classe abstraite. Avec l'abstraction de classe et gcc, le temps de calcul d'une addition est quand même multipliée par 13!

    Tu ne vas donc pas mélanger les différents types de valeurs, parce que cela reviendrait à mélanger... les pommes et les poires
    Sauf quand tu veux savoir si la couleur de tes pommes est corrélée à celle de tes poires.

    Plus sérieusement, merci pour l'idée de la spécialisation ça va me faire gagner un niveau de hiérarchie!

  5. #45
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Re,

    j'ai encore une question...

    Pour la spécialisation, est-il utile d'empêcher la construction d'un objet pour les types non souhaités (classe non copiable dans la faq je crois)?
    Par exemple, dans l'exemple donné koala01, j'aurais voulu écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template<typename T>
    class Classe
    {
    private:
         Classe();
         Classe(Classe const&);
         Classe& operator=(Classe const&);
    };

  6. #46
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Le choix de mettre où non le constrcuteur de copie et l'opérateur d'affectation dépend de la sémantique de ta classe : entité où valeur. (cf la faq pour les détails)

    En général il faut quand même que ta classe comporte un constructeur, sinon tu pourras pas en faire grand chose (où un système qui retourne une instance comme pour les singleton).

    Si ta question concerne le que faire pour les type dont tu ne veut pas que ton template gère, alors la réponse est rien.

    Le code de koala fonctionne car il ne définit pas la classe template pour un type quelconque, il ne fait que la déclarer, ce qui conduit à une erreur si tu l'utilise sur un type où il n'y a pas de spcialisation définit.

  7. #47
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Je voudrais dire mon avis concernant la définition d'une classe "superpolymorphe" et de tableaux qui pourraient contenir des valeurs de n'importe quel type.

    Mon projet traite de Conception et Dessin assisté par ordinateur.
    J'ai 3 type de de base
    1- le point
    2- la ligne
    3- l'objet.

    Un point (XYZ), sauf s'il possède un Z, n'est pas utile en lui-même
    Une ligne peut être brisée ou non, fermée ou non, formant zone ou non etc. Mais si elle est réduite à un point ce n'est plus une ligne.
    Un objet est n'importe quoi qui comporte un certain nombre d'éléments possibles, mais strictement définis. Par exemple un texte, l'origine de ce texte, une liste de lignes, d'objets, un descriptif, une notion de couche (cf SIG) etc.
    Ces 3 types fondamentaux possèdent un matricule.
    Un matricule possède les informations d'identification concernant l'élément correspondant (Point-Ligne-Objet) ainsi que des caractéristiques de visibilité et autres.

    J'explique cela pour dire que cela ne me semble pas une bonne idée de créer une classe NOMBRE. Le langage est très typé, faire une organisation qui passe au-dessus de ce typage annulerait à la base l'un des principes fondamentaux du langage.
    De la même façon que dans mon projet, j'aurais pu n'avoir qu'un seul type : OBJET, la suite m'a montré que j'avais fait le bon choix, puisque les très nombreux rajouts sont toujours rentrés dans le cadre de base, sans modification.

    Naturellement, je pourrais développer ce sujet, si ça intéresse quelqu'un.

  8. #48
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour Flob90,

    merci de venir donner un petit coup de main!

    Citation Envoyé par Flob90 Voir le message
    Le choix de mettre où non le constrcuteur de copie et l'opérateur d'affectation dépend de la sémantique de ta classe : entité où valeur. (cf la faq pour les détails)
    Je vais regarder ça tout de suite.

    Citation Envoyé par Flob90 Voir le message
    En général il faut quand même que ta classe comporte un constructeur, sinon tu pourras pas en faire grand chose (où un système qui retourne une instance comme pour les singleton).
    Oui, je voulais faire un truc comme ça :
    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
     
    template<typename T>
    class Classe
    {
    private:
    	Classe();
    	Classe(const Classe&);
    	Classe& operator=(Classe const&);
    private:
    	T _val;
    };
     
    template<> class Classe<double>
    {
    public:
    	Classe();
    	Classe(double const&);
    	Classe(Classe<double>const&);
    	double& operator=(Classe<double>const&);
    	double& operator=(double const&);
    };
    Le code de koala fonctionne car il ne définit pas la classe template pour un type quelconque, il ne fait que la déclarer, ce qui conduit à une erreur si tu l'utilise sur un type où il n'y a pas de spcialisation définit.
    Je pensais que le constructeur par défaut, le constructeur par copie et l'opérateur d'assignation étaient définis automatiquement.
    Ce n'est plus le cas en cas de spécialisation?

    EDIT : je crois que je viens de comprendre ce que tu veux dire. Il faut juste faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<typename T>
    class Classe;   // rien n'est défini automatiquement
    et surtout pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<typename T>
    class Classe{}; // définitions automatiques (constructeurs par défaut/copie, surcharge de =)

  9. #49
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    Concernant la hiérarchisation ce n'est plus mon problème : je ne m'occupe que de l'existant.
    Pour la spécialisation, je pars du principe qu'il ne faut pas modifier l'encapsulation existante (constructeurs protégés ou classes abstraites).
    Mais je suis d'accord c'est techniquement possible.
    Même avec des classes abstraites et des constructeurs protégés pour une classe de base, tu n'est pas à l'abri du fait que quelqu'un décide de faire dériver une classe "à lui" de cette classe de base.

    Tu dois donc veiller à fournir ce qui te semble intéressant et, pour la suite, tant pis si l'utilisateur fait quelque chose de mal à partir de là
    J'espère que tu n'attends pas une réponse de ma part : je n'ai pas compris...
    Je reformule:

    Qu'est-ce qui est préférable selon toi

    De permettre un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    TaClass c;
    /* calcul des valeurs de x et de y */
    c.setMachin(x);
    c.setTruc(y);
    ou de forcer l'utilisateur à réfléchir dans l'autre sens, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /* calcul des valeurs de x et de y */
    TaClass c(x,y);
    /* quitte à permettre l'utilisation de
     * TaClass(0,0);
     */
    De manière générale, la seconde pratique est "meilleur" car tu as la certitude que tout objet créé est correctement initialisé quitte à ce que ce soit, effectivement, avec une valeur considérable comme étant nulle.

    Pour le reste, c'est ta définition de tes opérateurs arithmétique qui se chargera de modifier (ou non, selon qu'il y ait ou non affectation) ton objet
    La raison pratique c'est de pouvoir stocker des tableaux de données quantitatives (numériques), qualitatives et nominales pour faire de l'apprentissage statistique (les trois types de données pouvant bien sûr coexister dans un même tableau).
    A ce stade, les opérations à effectuer ne sont ni plus ni moins celles d'un bête tableur.
    Attention, tu peux, effectivement, avoir des données quantitative et des données qualitatives dans ton tableau, mais, si tu effectue des calculs sur les données quantitative, tu ne va absolument pas utiliser les données qualitative pour autre chose que de te permettre de... trier tes données quantitatives, et inversement.

    Tu entres donc dans un contexte dans lequel tu a beaucoup plus besoin de tuple (une donnée quantitative correspond à un donnée qualitative) que dans celui dans lequel les deux doivent se retrouver "en vrac" dans ton tableau


    Après, il y a effectivement un prétraitement de données et je me retrouve avec des données numériques uniquement (le cas que tu envisages).
    Les tableaux sont volumineux et j'y accède souvent : je ne peux pas me permettre de stocker en ram la copie "mixte" et la copie "numérique".

    Je suis entièrement d'accord avec toi pour les questions de précision numérique mais dans ce cas particulier je ne suis pas concerné.
    C'est donc bien la preuve que tu vas toujours mettre... des valeurs de type identique dans ton tableau, dés lors, pourquoi s'embêter à vouloir que tous ces types de valeurs aient une base commune


    De ce que j'ai pu constater, cela ne prend pas du tout de temps tant que je n'ai pas de classe abstraite. Avec l'abstraction de classe et gcc, le temps de calcul d'une addition est quand même multipliée par 13!



    Sauf quand tu veux savoir si la couleur de tes pommes est corrélée à celle de tes poires.

    Plus sérieusement, merci pour l'idée de la spécialisation ça va me faire gagner un niveau de hiérarchie!
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #50
    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 Aleph69 Voir le message
    Je ne trouve pas d'exemple où ce serait nécessaire.
    Tu peux expliquer pourquoi?
    Ben, tu voudrais qu'ils soient mieux "intégrés" au langage, plutôt que d'être une "bête" classe. Pour ça, il faudrait, tout comme on a 'f' pour les floats etc, avoir quelque chose qui permet d'indiquer qu'on est en présence d'un nombre complexe. Pour ça il faudrait pouvoir donc avoir un 'i' dans le langage, pour pouvoir écrire "1+i" par exemple. Or ça entrerait en conflit avec toutes les indices de boucle et autres que David mentionne.

    Citation Envoyé par Davidbrcz Voir le message
    Tain, je suis décidément pas réveillé ><. Sinon, je rejoins ton avis dessus, en rien. Suffit de créer une structure avec deux membres et les fonctions libres qui vont bien (vu que le C ne supporte pas la surcharge d'opérateur)
    Ben c'est déjà le cas avec std::complex, or là il parlait d'avancer et de mieux intégrer ça, l'étape qui vient juste après c'est d'avoir une intégration dans le langage, donc d'avoir "i" d'une façon ou d'une autre. Parce que ce dont tu parles c'est std::complex quoi.

    Et sinon, on paramètre les types de valeurs parce que on veut pouvoir avoir des niveaux de précision différents, ou alors ne jouer qu'avec les entiers de Gauss ou quoi. La mentalité du C++ c'est pas d'offrir l'interface la plus simple ou quoi, c'est d'offrir des outils efficaces, génériques (et donc réutilisables).

    Et sinon, tu peux détailler un peu plus ton projet ? On pourra peut-être mieux t'aider niveau design si on a une meilleure idée globale de ce que tu dois accomplir.

  11. #51
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    Je pensais que le constructeur par défaut, le constructeur par copie et l'opérateur d'assignation étaient définis automatiquement.
    Ce n'est plus le cas en cas de spécialisation?
    Il faut faire la distinction entre la déclaration d'une classe et sa définition.

    Quand tu écris simplement le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class MaClasse;
    /* OU OU OU */
    template <class T>
    class ClassTemplate;
    Tu ne fais que déclarer la classe.

    Bref, cela revient à lui dire "il existe une classe nommée MaClasse" ou "il existe une classe générique nommée ClassTemplate".

    !!! Mais il ne sait pas encore "de quoi elle est faite" !!!

    Cela permet juste au compilateur, qui ne connait que ce qu'il a déjà rencontré, de savoir qu'il existe un symbole correspondant à la classe déclarée (c'est, par exemple, utile pour les références croisées entre deux classes)

    La définition d'une classe va lui "donner un corps" en indiquant au compilateur son contenu.

    C'est ce que tu fais lorsque tu écris
    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
    class MaClass
    {
        public:
            /* l'interface publique */
        private:
            /* les membres privés */
    };
    /* OU OU OU la spécialisation partielle ou totale 
     *de la classe template
     */
    template <>
    class ClassTemplate<int>
    {
        public:
            /* l'interface publique */
        private:
            /* les membres privés */
    };
    La création automatique de Big Four (constructeur trivial, constructeur par copie, opérateur d'affectation et destructeur) n'a lieu que... au moment de la définition de la classe, si, bien sur, le compilateur se trouve dans une situation dans laquelle il estime devoir les implémenter automatiquement.

    De la même manière que, dans le cadre de deux classes présentant des références croisées, tu ne peut accéder au contenu d'une d'elles depuis l'autre qu'une fois que tu en a donner la définition, lorsque tu décide de créer une instance de ClassTemplate pour un type donné, il va chercher... le corps de cette classe.

    Si il trouve une spécialisation qui convient parmis celles que tu as données, il va l'utiliser.

    Autrement, il te dira qu'il ne trouve pas la définition de ClassTemplate < QuelqueChose>
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #52
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je n'ai toujours pas bien compris pourquoi tu ne peux (veux ?) pas passer par un variant pour ton histoire de collection.

    Ca répond au besoin (ou alors, détaille plus le besoin ), et ça t'évite les problèmes que tu as avec l'héritage.

  13. #53
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    tout d'abord merci beaucoup pour votre aide.
    L'idée de la spécialisation m'a bien aidé.

    Je répond rapidement aux remarques :

    @koala01 : je suis d'accord avec toi pour l'initialisation par défaut des objets.

    @Pierre : la réponse juste au-dessus justifie (dans mon cas) la réprésentation des nombres par des classes (initialisation par défaut).

    @Alp : je ne comprends toujours pas cette histoire de nombre complexe. Pourquoi ne pourrait-on pas faire comme en Fortran par exemple?


    Citation Envoyé par Alp Voir le message
    Et sinon, tu peux détailler un peu plus ton projet ? On pourra peut-être mieux t'aider niveau design si on a une meilleure idée globale de ce que tu dois accomplir.
    En gros, le projet va être constitué de trois grosses briques :
    1. un noyau d'algèbre linéaire dense et creuse,
    2. un noyau de statistique exploratoire et d'apprentissage automatique,
    3. une interface homme-machine.

    Pour l'instant, je m'occupe du deuxième point.
    Pour simplifier, le noyau va servir à extraire de la connaissance à partir de données contenus dans des tables (type Excel).
    Chaque colonne représente une variable décrivant le phénomène étudié (température, couleur de peau, âge, ...).
    Chaque ligne représente une expérience.
    L'idée est de tirer des généralités à partir d'un nombre fini d'expériences.
    C'est par exemple ce qu'on fait pour les sondages : on interroge un nombre de personnes et on en déduit une prédiction sur toute la population.

    Chaque case d'un tableau peut contenir l'une des données suivantes :
    1. donnée numérique (température, pression, ...),
    2. donnée ordinale, i.e. qui n'est pas un nombre mais présente une relation d'ordre (faible/moyen/élevé, enfant/adolescent/adulte, ...),
    3. donnée qualitative (pays, sexe, ...),
    4. donnée manquante (donnée qui n'a pu être mesurée)

    Il est important de savoir ce qu'on manipule car les méthodes que l'on va appliquer vont varier en fonction des types de données.
    Il y a un prétraitement qui transforme les variables ordinales et quantitatives en nombres.
    Les valeurs manquantes sont classiquement représentées par NaN.

    Je peux entrer plus dans les détails si nécessaire (méthodes utilisées, etc).

    Donc, pour l'instant, j'ai une classe Dataset qui représente mes tables.
    Elle dispose d'un constructeur qui lit un fichier de données donné en paramètre.
    Au niveau des données membres, c'est un tableau de Data.
    La classe Data sert à représenter tout type de donnée.
    La classe Number dont on parle depuis le début de cette discussion est utilisée pour représenter les données numériques.
    Grâce au prétraitement cité précédemment, on peut manipuler un Dataset comme une matrice.
    Typiquement, on va faire :
    1. de la décomposition en valeurs singulières pour l'ACP,
    2. des calculs de distances entre vecteurs ligne pour la classification (CAH, cartes de Kohonen)
    3. calculs divers sur les colonnes (centrage, réduction, sélection/extraction de variables).

    L'approche la plus naïve qui me vienne à l'esprit consisterait à construire une matrice de flottants et à stocker à part dans un tableau 1D les types des variables à l'aide d'une énumération.
    Le problème c'est que c'est coûteux en mémoire et en temps de calcul.

    A l'heure actuelle, j'ai donc plutôt un objet par type de donnée.

    Après réflexion, il a peut-être moyen de faire un mix des deux solutions en utilisant les templates pour faire une matrice contenant plusieurs types de nombres (short, int, float, double, etc) et en conservant à part le type de donnée de chaque variable mais je ne sais pas si c'est techniquement possible.

    Voilà, j'espère que c'est assez clair.
    Si besoin je peux répondre à toutes les questions, il n'y a rien de confidentiel.

Discussions similaires

  1. Héritage SQL et performances
    Par BigFoot69 dans le forum Décisions SGBD
    Réponses: 17
    Dernier message: 18/04/2014, 17h16
  2. héritage et destructeurs virtuels.
    Par deubelte dans le forum C++
    Réponses: 19
    Dernier message: 08/04/2010, 10h42
  3. [MLD] Héritage et performances
    Par ymoreau dans le forum Schéma
    Réponses: 8
    Dernier message: 09/07/2009, 09h35
  4. Gotw #5 héritage et destructeur virtual
    Par Trunks dans le forum Langage
    Réponses: 7
    Dernier message: 07/04/2009, 14h56
  5. Thread, Héritage et Destructeurs
    Par contremaitre dans le forum Threads & Processus
    Réponses: 8
    Dernier message: 15/09/2008, 10h20

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