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 :

probleme avec constructeur


Sujet :

C++

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Mai 2013
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2013
    Messages : 75
    Par défaut probleme avec constructeur
    Bonjour,

    comme indiqué j'ai un problème avec mon constructeur lorsque j'essaie de créer une classe. (je code sur Microsoft Visual Studio 2010)

    J'ai créé une classe Line_hough dans le but d'utiliser une transformé de Hough

    Et en fonction de mes sources j'obtiens plusieurs manières de créer un constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	Line_hough::Line_hough(){
    		deltaRho=1;
    		deltaTheta=PI/180;
    		minVote=10;
    		minLength=0;
    		maxGap=0;
    	}
    m'indique le problème suivant :

    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(27): error C3254: 'Line_Hough'*: la classe contient une substitution explicite '{ctor}', mais ne dérive pas d'une interface qui contient la déclaration de fonction
    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(27): error C2838: '{ctor}'*: nom qualifié non conforme dans une déclaration de membre
    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(67): fatal error C1004: fin de fichier inattendue rencontrée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	Line_hough(){
    		deltaRho=1;
    		deltaTheta=PI/180;
    		minVote=10;
    		minLength=0;
    		maxGap=0;
    	}
    ==>

    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(27): error C4430: spécificateur de type manquant - int est pris en compte par défaut. Remarque*: C++ ne prend pas en charge int par défaut
    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(33): warning C4183: 'Line_hough'*: type de retour manquant*; fonction membre retournant 'int' prise par défaut
    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(67): fatal error C1004: fin de fichier inattendue rencontrée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Line_hough():deltaRho(1), deltaTheta(PI/180), minVote(10), minLength(0), maxGap(0){}
    ==>

    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(25): error C2590: 'Line_hough' : seul un constructeur peut avoir une liste d'initialiseurs de base/membre
    1>c:\documents and settings\sy_r\mes documents\visual studio 2010\projects\open_cv\open_cv\line_hough.cpp(67): fatal error C1004: fin de fichier inattendue rencontrée

    Je ne comprend pas trop la différence entre ces méthodes et pourquoi elles ne fonctionnent pas ?

    Cordialement,
    Ronan


    Voici le code complet du .cpp :


    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
    #include "Line_hough.h"
    # include "cv.h"
    # include "highgui.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <vector>
    #include <string>
    using namespace cv;
    using namespace std;
     
    class Line_Hough{
     
    	cv::Mat img;
     
    	std::vector<Vec4i> lines;
     
    	double deltaRho;
    	double deltaTheta;
     
    	int minVote;
    	double minLength;
    	double maxGap;
     
     
    	Line_hough():deltaRho(1), deltaTheta(PI/180), minVote(10), minLength(0), maxGap(0){}
     
    	/*Line_hough(){
    		deltaRho=1;
    		deltaTheta=PI/180;
    		minVote=10;
    		minLength=0;
    		maxGap=0;
    	}*/
     
    	void setAccResolution(double dRho, double dTheta){
    		this->deltaRho=dRho;
    		this->deltatTheta=dTheta;
    	}
     
    	void setMinvote(int minv){
    		this->minVote=minv;
    	}
     
    	void setLineLengthAndGap(double length, double gap){
    		this->minLength=length;
    		this->maxGap=gap;
    	}
     
    	std::vector<Vec4i> findLines(Mat& binary){
    		lines.clear();
    		HoughLinesP(binary,lines,deltaRho,deltaTheta,minVote,minLength,maxGap);
    		return lines;
    	}
     
    	void drawDetectedLines(Mat &image,Scalar color=cv::Scalar(255,255,255)){
    		std::vector<Vec4i>::const_iterator it2=lines.begin();
     
    		while(it2!=lines.end()){
    			Point pt1((*it2)[0],(-it2)[1]);
    			Point pt2((*it2)[2],(*it2)[3]);
    			line(image,pt1,pt2,color);
    			++it2;
    		}
    	}
     
    }
    et voici le code complet du .h :

    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
    #ifndef LINE_HOUGH_H
    #define LINE_HOUGH_H
     
    # include "cv.h"
    # include "highgui.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <vector>
    #include <string>
    using namespace cv;
    #define PI 3.1415926;
     
    class Line_hough
    {
    public:
    	Line_hough();
    	void setAccResolution(double dRho, double dTheta);
    	void setMinvote(int minv);
    	void setLineLengthAndGap(double length, double gap);
    	std::vector<Vec4i> findLines(Mat& binary);
    	void drawDetectedLines(Mat& image,Scalar color=Scalar(255,255,255));
    };
     
    #endif

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 751
    Par défaut
    Sans être méchant, apprends le C++. Là tu as un mix Java/ C++/ catégorie Objective-C

    Et SVP
    1. Supprime tous les this->
    2. N'utilise pas la liste d'initialisation pour des types atomique


    Édit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define PI 3.14159265358979323846

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Mai 2013
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2013
    Messages : 75
    Par défaut
    c'est justement en essayant d'apprendre que je suis tombé sur ces formes ...

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par foetus Voir le message
    N'utilise pas la liste d'initialisation pour des types atomique
    Qu'apelles-tu type atomique ? Les types primitifs ?
    Et pourquoi alors ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour Ronan.


    A en voir ton header ( fichier .h) et ton fichier source (fichier .cpp), tu as mélangé un peu header et source.
    C'est déjà très bien que tu aies séparé ta classe en deux fichiers, et voilà comment je m'y prends:

    Dans ton header, on configure la classe, en spécifiant explicitement les attributs (variables internes de ta classe), les prototypes des méthodes (fonctions), les prototypes du/des constructeurs + du destructeur. Et enfin on spécifie la portée de tes méthodes/attributs (si elles peuvent être accessibles (à la lecture tout comme à l'écriture) par d'autres classes).


    Voilà à quoi pourrait ressembler un header (le nom de ma classe: "MyObject") :

    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
    #ifndef __MY_OBJECT_H__ // information que l'on fournit au compilateur pour éviter la multi-inclusion. Un define différent par classe est recommandé.
    #define __MY_OBJECT_H__
     
    class MyObject
    {
    public: Ce  qu il y a en dessous de ce mot-clef est accessible par tout le monde dans ton code.
    MyObject(); // constructeur par défaut.
    MyObject(const double& entree_1 , const int& entree_2); // constructeur avec deux arguments.
    ~MyObject(); // destructeur.
     
    void afficher_resultat() const ; // le mot-clef "const" est à mettre si la fonction ne modifie pas les attributs de ta classe.
    void modifier_attribut();
     
    int m_int_attribut; // un attribut public.
    private: Ce qu il y a en dessous de ce mot-clef n est accessible QUE par des objets de type MyObject
    double m_double_attribut; // un attribut privé.
    int calculer_somme(const int& entier_1 , const int& entier_2) const;
     
    };
     
    #endif
    Comme tu peux le voir, il n'y a pas d'ordre spécifique dans le header: on peut mettre les attributs avant ou après les méthodes, c'est pas très important (pour le compilateur en tout cas, après pour la compréhension du code c'est autre chose ), tant qu'ils sont bien positionnés par rapport aux mots-clefs "public" ou "private".


    C'est uniquement dans le fichier .cpp qu'il faut s'amuser à initialiser/implémenter tout ce petit monde . Voilà à quoi pourrait ressembler le .cpp:

    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
    #include "MyObject.h" // et oui faut pas l'oublier lol
     
    MyObject::MyObject() // ATTENTION: il ne faut pas oublier le "MyObject::" devant chacune des méthodes, afin de spécifier au compilateur qu'on implémente bien la fonction déclarée dans le header !! 
        : m_int_attribut(0) // on peut initialiser un attribut comme ceci...
    {
        m_double_attribut = 0.0; // ... ou comme cela...
    }
     
    MyObject::MyObject(const double& entree_1 , const int& entree_2)
        : m_int_attribut(entree_2) // on peut initialiser un attribut comme ceci...
    {
        m_double_attribut = entree_1; // ... ou comme cela...
    }
     
    MyObject::~MyObject()
    {
    }
     
    void MyObject::afficher_attribut_int() const // ATTENTION: on n'oublie pas le mot-clef "const" ^^
    {
         std::cout << "Attribut_int = " << m_int_attribut << std::endl;
    }
    void MyObject::modifier_attribut()
    {
        m_int_attribut  = m_int_attribut + 5; //modification d'attribut.
    }
     
    int MyObject::calculer_somme(const int& entier_1 , const int& entier_2) const
    {
        return entier_1 + entier_2;
    }


    Tout cela pour dire que les attributs doivent être déclarées dans le header, et non dans le fichier source comme tu l'as fait.

  6. #6
    Membre confirmé
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Mai 2013
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2013
    Messages : 75
    Par défaut
    parfait merci pour votre aide

    Cordialement,

    Ronan

  7. #7
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Citation Envoyé par Boumbata Voir le message
    C'est déjà très bien que tu aies séparé ta classe en deux fichiers
    Ne pas séparer la définition et la déclaration ou les séparer mais dans le même fichier est "très bien" aussi
    C'est un choix personnel et je déteste maintenir deux fois la même chose. (Pour l'utilisation, préférer la Doxygen)

    Citation Envoyé par Boumbata Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #ifndef __MY_OBJECT_H__ // information que l'on fournit au compilateur pour éviter la multi-inclusion. Un define différent par classe est recommandé.
    #define __MY_OBJECT_H__
    FAQ C++ - Quels sont les identificateurs interdits par la norme ?

    Citation Envoyé par Boumbata Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_int_attribut; // un attribut public.
    Généralement, les attributs publics ne commencent pas par m_.

    Citation Envoyé par Boumbata Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ~MyObject(); // destructeur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MyObject::~MyObject()
    {
    }
    Ce destructeur est généré par défaut par le compilateur.
    C++11 FAQ - control of defaults: move and copy

    Citation Envoyé par Boumbata Voir le message
    Généralement on ne prend pas les types de base en référence sur membre constant mais on fait une copie constante : double const d.
    + La règle du const : FAQ C++ - Quelle est la différence entre char*, const char* et char const * ?

    Citation Envoyé par Boumbata Voir le message
    Comme tu peux le voir, il n'y a pas d'ordre spécifique dans le header: on peut mettre les attributs avant ou après les méthodes, c'est pas très important (pour le compilateur en tout cas, après pour la compréhension du code c'est autre chose ), tant qu'ils sont bien positionnés par rapport aux mots-clefs "public" ou "private".
    Petite précision : l'ordre d'initialisation des attributs par le constructeur "doit" suivre celui de la déclaration des attributs.

    Citation Envoyé par Boumbata Voir le message
    C'est uniquement dans le fichier .cpp qu'il faut s'amuser à initialiser/implémenter tout ce petit monde .
    On peut aussi le faire dans le header lui-même ou un autre header

    Citation Envoyé par Boumbata Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    MyObject::MyObject() // ATTENTION: il ne faut pas oublier le "MyObject::" devant chacune des méthodes, afin de spécifier au compilateur qu'on implémente bien la fonction déclarée dans le header !! 
        : m_int_attribut(0) // on peut initialiser un attribut comme ceci...
    {
        m_double_attribut = 0.0; // ... ou comme cela...
    }
    En C++, on utilise la liste d'initialisation pour initialiser les attributs. Dans le corps du constructeur, c'est une affectation (pas une initialisation).

    Citation Envoyé par Boumbata Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void MyObject::afficher_attribut_int() const // ATTENTION: on n'oublie pas le mot-clef "const" ^^
    {
         std::cout << "Attribut_int = " << m_int_attribut << std::endl;
    }
    Généralement on surcharge l'opérateur << entre un std::ostream et le type. C'est une fonction libre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    std::ostream & operator<<(std::ostream & o, MyObject const & a)
    {
        o << "Attribut_int = " << a.m_int_attribut;
        return o;
    }
    PS: Attention à l'indentation.

  8. #8
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    Ne pas séparer la définition et la déclaration ou les séparer mais dans le même fichier est "très bien" aussi
    C'est un choix personnel et je déteste maintenir deux fois la même chose. (Pour l'utilisation, préférer la Doxygen)
    C'est parfois utile et nécessaire, mais ne pas séparer (ou séparer dans le même header) pose quand même un assez gros souci (lié au modèle de compilation du C++ et à la façon dont sont gérés les header) : tout fichier qui inclue ton header (et donc qui utilise ce qu'il déclare) devient dépendant d'un changement de la définition et on se retrouve ainsi à devoir recompiler des dizaines de fichiers pour une simple modification de l'implémentation qui ne les concerne pas vraiment. Dans un gros projet ça devient vite assez lourd.

    Quant à ne pas maintenir deux fois la même chose, je suis dubitatif : l'interface est quand même beaucoup plus stable que l'implémentation. Certes lors d'un ajout du va devoir le faire à deux reprises mais ça me semble assez mineur comme souci, de moindre importance que le point précédent (tout au moins dans le type de projet sur lesquels je travaille).

  9. #9
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Il y a des avantages et des inconvénients. En effet, le temps de compilation peut être dramatique en header-only.
    Citation Envoyé par gl Voir le message
    fichier qui inclue ton header (et donc qui utilise ce qu'il déclare) devient dépendant d'un changement de la définition
    mais la dépendance reste la même qu'avec une bibliothèque compilée (il faudra mettre à jour le .so ou équivalent).
    (On peut limiter la casse en multipliant le nombre de fichiers d'entête.)

    L'avantage d'une bibliothèque header-only est sa facilité de distribution

  10. #10
    Invité
    Invité(e)
    Par défaut
    Merci pour les précisions/corrections apportées Ehonn
    Dernière modification par Invité ; 06/05/2014 à 12h50.

  11. #11
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    mais la dépendance reste la même qu'avec une bibliothèque compilée (il faudra mettre à jour le .so ou équivalent).
    (On peut limiter la casse en multipliant le nombre de fichiers d'entête.)
    Dans le cas d'une bibliothèque, tu n'as que le temps de compilation des fichiers modifiés puis la génération de la bibliothèque et éventuellement (ce n'est pas le cas dans la cas d'un chargement dynamique) de l'édition de lien de l'appli.

    Dans l'autre cas tu recompiles tous les fichiers qui inclus le header modifié, y compris ceux qui n'ont que faire de la modification et l'édition de lien. Si le nombre de fichiers concernés est important (et ça le devient rapidement surtout si le header est question est une brique de base) le temps devient très largement supérieur à celui de la génération de la bibliothèque.

    Citation Envoyé par Ehonn Voir le message
    L'avantage d'une bibliothèque header-only est sa facilité de distribution
    Tout à fait. C'est d'ailleurs ce qui me fait dire que ça peut être utile aussi.


    Mais là on touche deux soucis du C++ actuel :
    • Le modèle de compilation / inclusion des header hérité du C (mais un modèle ne distinguant pas interface et implémentation ne me conviendra pas davantage). J'attends beaucoup des modules à ce sujet (il faudrait d'ailleurs que je regarde où ça en est).
    • L'absence d'ABI standardisée (pour la facilité de distribution des bibliothèques).

  12. #12
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 751
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Qu'apelles-tu type atomique ? Les types primitifs ?
    Et pourquoi alors ?
    Je te réponds ... avec un peu de retard

    Parce que le C++ permet des choses qui peuvent porter à confusion.

    Pour la liste d'initialisation, elle sert juste à appeler un autre constructeur et initialiser les variables statiques (il me semble )
    Effectivement, on peut mettre aussi les attributs de type atomique (int, short, char, long, ...).

    Mais dans ce cas la syntaxe ressemble fortement à un appel de constructeur ... alors qu'il n'y a pas de constructeur

    Après avec l'expérience c'est une question de goût: soit on a une liste d'initialisation à rallonge, soit on a des lignes d'affectations.

    D'ailleurs Ehonn fait une précision pour lever l'ambiguïté
    En C++, on utilise la liste d'initialisation pour initialiser les attributs. Dans le corps du constructeur, c'est une affectation (pas une initialisation).
    On peut faire la même remarque avec l'appel du constructeur avec l'opérateur new: est-ce une fonction ou une type atomique?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        Toto* t = new Toto;
    //  Toto* t = new Toto();
        delete t;
    Édit: @Ehonn

  13. #13
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    La liste d'initialisation "doit" initialiser tous les attributs.
    Les types de bases (int, char, ...) sont (assimilés à) des POD et ont un constructeur (par défaut et par copie).
    new est un opérateur (qu'il "ne faut pas" utiliser (en C++ moderne)). Dans ton exemple, t est initialisé. Lorsqu'on utilise new, on utilise delete, pas free.

  14. #14
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    Tu confonds tout et n'utilises pas les bon termes.

    On parle de types primitifs. Atomique est quelque chose de totalement différent, et on parle d'opération atomique.

    La liste d'initialisation sert à initialiser un attribut.
    Tout comme on écrira int i = 0; et non Encore que, merci à eux, les compilateurs savent maintenant optimiser ça justement.

    L'affectation dans le constructeur, son nom indique justement ce dont il s'agit.
    Puisque c'est une affectation, la variable existe déjà et a déjà une valeur par défaut.
    Dans le cadre d'un type primitif, on s'en moque, sa valeur ne sera qu'un résidu de la mémoire précédemment utilisée.
    Dans la cadre d'un objet c'est déjà plus chiant, puisqu'on aura l'appel au constructeur par défaut (encore faut-il qu'il existe !), puis l'appel à operator=. Inutile d'être un gourou pour se rendre compte que sur un objet complexe ça peut être très gourmand.
    Btw, c'est la seule manière d'initialiser une référence.
    Autant tout mettre dans la liste d'initialisation : bonne pratique, regroupement des initialisations, lecture du code améliorée.
    La confusion, franchement je vois pas.
    Heureusement encore, la plupart des compilateurs savent maintenant optimiser ça pour les programmeurs étourdis.

    La précision d'Ehonn est juste une une connaissance plus ou moins avancée de la programmation en C++.

    Les variables statiques ne devraient jamais être initialisées dans la liste d'initialisation.
    Si elles le sont, et je n'ai jamais vu le cas, il y a certainement une raison très particulière, mais c'est strictement du cas particulier.

    Les pointeurs n'y font absolument pas exception. Toto* t; ne fera que déclarer un pointeur. Sur quoi il pointe ? On ne sait pas, et probablement un truc inutilisable qui entraînera un crash si l'on essaye.
    Le new ne fait qu'un appel explicite à un constructeur et crééer de la mémoire qui ne sera pas supprimée lors de la sortie de portée.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  15. #15
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par foetus Voir le message
    On peut faire la même remarque avec l'appel du constructeur avec l'opérateur new: est-ce une fonction ou une type atomique?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        Toto* t = new Toto;
    //  Toto* t = new Toto();
        delete t;
    La syntaxe new fonction(); n'existe pas. C'est forcément new type; ou new (adresse_ou_fonction_renvoyant_une_adresse) type;.

    Ca rend la réponse à la question assez simple : parenthèses ou pas, c'est un type.

  16. #16
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 751
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    Les types de bases (int, char, ...) sont (assimilés à) des POD et ont un constructeur (par défaut et par copie).


    Citation Envoyé par Ehonn Voir le message
    new est un opérateur (qu'il "ne faut pas" utiliser (en C++ moderne)).
    Tu fais comment pour allouer?



    Citation Envoyé par Bousk Voir le message
    On parle de types primitifs. Atomique est quelque chose de totalement différent, et on parle d'opération atomique.
    Il y a bien une notion de 1: std::atomic, mais il n'y a pas les flottants

    Citation Envoyé par Bousk Voir le message
    La liste d'initialisation sert à initialiser un attribut.
    Non à créer en premier: pour preuve toi même tu dis que c'est pour appeler les constructeurs (et je l'ai dit aussi )

    Après tu peux jouer sur les mots ... un peu comme moi

    Tu as dit:
    Puisque c'est une affectation, la variable existe déjà et a déjà une valeur par défaut.
    ou alors
    Dans le cadre d'un type primitif, on s'en moque, sa valeur ne sera qu'un résidu de la mémoire précédemment utilisée.

    Citation Envoyé par Bousk Voir le message
    Dans la cadre d'un objet c'est déjà plus chiant, puisqu'on aura l'appel au constructeur par défaut (encore faut-il qu'il existe !), puis l'appel à operator=. Inutile d'être un gourou pour se rendre compte que sur un objet complexe ça peut être très gourmand.
    Dans un autre sens, mettre un objet en attribut et non pas un pointeur ni une référence, le développeur doit s'attendre à un appel d'un constructeur par défaut et faire attention au recopie. Tu ne crois pas?

    Citation Envoyé par Bousk Voir le message
    Les variables statiques ne devraient jamais être initialisées dans la liste d'initialisation
    Oui tu as raison fqa 10.10


    Citation Envoyé par Iradrille Voir le message
    La syntaxe new fonction(); n'existe pas. C'est forcément new type; ou new (adresse_ou_fonction_renvoyant_une_adresse) type;.

    Ca rend la réponse à la question assez simple : parenthèses ou pas, c'est un type.
    Tu vas me dire quoi pour ce bout de code alors?

    Pourtant le constructeur est bien une méthode

    Et pour le int, comme Ehonn: on appelle le constructeur de int. Ou alors la fonction int

    On ne fait pas de new en C++ moderne

    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
    #include<iostream>
     
    class Toto {
    public:
     
        Toto() {
            std::cout << "Default Constructor" << std::endl;
        }
     
        Toto(int a) {
            std::cout << "Constructorn parameter: " << a << std::endl;
        }
    };
     
     
    int main(void)
    {
        Toto* t = new Toto;
        delete t;
     
        t = new Toto(5);
        delete t;
     
        int* i = new int(5);
        std::cout << "i: " << (*i) << std::endl;
        delete i;
     
        return 0;
    }

  17. #17
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par foetus Voir le message
    Tu vas me dire quoi pour ce bout de code alors?

    Pourtant le constructeur est bien une méthode

    Et pour le int, comme Ehonn: on appelle le constructeur de int. Ou alors la fonction int
    Un constructeur est une méthode, oui. Mais après un new il n'y aura jamais d'appel de fonction, toujours un type.

    int n'est pas une fonction, c'est un type.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int *pi = new int(42); // il n'y à pas d'appel de fonction ici, qu'il y ait des parentheses ou non.
    // Seul l'opérateur new est appelé, c'est lui qui se charge d'appeler le constructeur.
     
    // new type(args); comme toujours
    // a peu près équivalent à 
    int *p = (int*) malloc(sizeof(int)); // Type *p = (Type*) malloc(sizeof(Type));
    new (p) int(42); // new (p) Type(args);
     
    // ce placement new peut etre vu comme un appel explicite au ctor : 
    p->int(42); // p->Type(args); bien sur ça ne compile pas.

  18. #18
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Pour allouer "sans new", tu utilises la pile (RAII). Tout objet en C++ s'utilise comme un type de base, son destructeur est automatiquement appelé à la fin du bloc. Pour le polymorphisme d'inclusion on utilisera un pointeur intelligent par exemple ou un boost::ptr_vector (il y a bien sur des new, mais new et delete n'apparaissent pas dans ton code).


    Par exemple ton code pourrait ressembler à ç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
    22
    23
    #include<iostream>
     
    class Toto
    {
    public:
     
        Toto() { std::cout << "Default Constructor" << std::endl; }
     
        Toto(int const a) { std::cout << "Constructorn parameter: " << a << std::endl; }
    };
     
     
    int main()
    {
        Toto t;
     
        t = Toto(5); // Construction d'un Toto temporaire + affectation (opérateur =)
     
        int i = 5;
        std::cout << "i: " << i << std::endl;
     
        return 0;
    }

  19. #19
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 392
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    La syntaxe new fonction(); n'existe pas. C'est forcément new type; ou new (adresse_ou_fonction_renvoyant_une_adresse) type;.

    Ca rend la réponse à la question assez simple : parenthèses ou pas, c'est un type.
    D'où tu sors "syntaxe new fonction()"? Le code que tu cites utilise new type() qui est parfaitement légal, et dans le cas des types POD diffère de new type (mais je te l'accorde, la différence n'a pas d'effet ici vu que Toto n'est pas POD).


    En C++ moderne, l'allocation dynamique "sans new" d'un objet seul se fait avec les pointeurs intelligent et les fonctions qui les construisent: make_unique() et make_shared().
    Par contre, si ton compilo est vieux, ces fonctions n'existent pas et tu te retrouve à utiliser new.
    Dans toutes les versions de C++, l'allocation dynamique "sans new" de plusieurs objets se fait avec les conteneurs de la STL, comme std::vector (passé par référence si ton compilo ne supporte pas la sémantique de transfert).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  20. #20
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    Un type atomique c'est un abus de langage.
    C'est les opérations qui sont atomiques, pour éviter les data races (accès concurrentiel à une donnée en environnement multi-thread).
    std::atomic ne fait que rendre toutes les opérations sur ta variable atomiques.
    Enfin std::atomic étant un template, t'y mets ce que tu veux, y compris des flottants.

    La liste d'initialisation est optionnelle. Si tu ne l'utilises pas, les objets seront quand même créés. Via leur constructeur par défaut pour les objets. Encore faut-il qu'ils en aient un. Via une valeur aléatoire, résidu de mémoire, pour un type primitif.

    Jouer avec les mots t'amuse peut-être, les comprendre serait mieux amha.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Probleme avec constructeur.
    Par watiero dans le forum C++
    Réponses: 18
    Dernier message: 15/02/2008, 16h16
  2. Probleme avec constructeur
    Par watiero dans le forum C++
    Réponses: 8
    Dernier message: 12/02/2008, 21h16
  3. Probleme avec constructeur surchargé
    Par dr971 dans le forum C++
    Réponses: 3
    Dernier message: 04/04/2007, 11h16
  4. Problème avec le constructeur SAXParser()!
    Par L4BiN dans le forum Format d'échange (XML, JSON...)
    Réponses: 5
    Dernier message: 21/06/2006, 09h32
  5. Réponses: 13
    Dernier message: 02/02/2005, 00h21

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