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 :

Template d'un constructeur d'une classe et pointeur


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut Template d'un constructeur d'une classe et pointeur
    Bonjour,

    J'ai défini ma classe vertex de cette manière (je reprends uniquement le constructeur, le reste étant hors sujet) :

    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
    class vertex
    {
    public:
    	/*
    	[Constructeur]
    	@param	dim				la dimension du point
    			coordinates		les coordonnées du point
    	*/
    	template<size_t dim>
    	vertex(double coordinates[dim])
    	{
    		this->dim = dim;
    		this->coordinates = new double[dim];
    		for(int i = 0; i < dim; ++i)
    			this->coordinates[i] = coordinates[i];
    	}
    private:
    	size_t dim;
            double * coordinates;
    }
    Je souhaiterais ensuite pouvoir écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    vertex *v = new vertex<3>(coordinates);
    Malheureusement, cette ligne ne compile pas. Le compilateur et l'IntelliSense de Visual Studio me disent qu'aucun constructeur par défaut n'existe pour la classe vertex. J'en déduis que l'expression ci-dessus est invalide.

    J'ai dû mal à voir où se situe l'erreur, pour autant que le constructeur soit lui-même valide.

    En vous remerciant d'avance,

    Nicolas.

  2. #2
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 149
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    syntaxe originale, mais on dirait qu'elle n'est pas possible !

    Tel quel, ton appel construit une classe template, hors c'est juste ton constructeur qui est template. (ce qui donne déjà des noeuds au cerveau amha).
    Le plus simple serait alors de mettre un constructeur par défaut, et de créer une autre méthode template (init, create, ...).
    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.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Ou alors, procéder comme avec le singleton: un "constructeur statique"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class vertex:
    private:
    vertex(double coordinates[], int size);
    public:
    template<int n>
    static vertex make(double coordinates[]);
    };
    Mais comme toujours, le tableau est rarement un bon choix. Je préfère de loin la paire d'itérateur.

    Ou, dans ce cas précis, templater la classe elle-même, quitte à créer une classe de base non template

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    La question à se poser est sans doute :
    Est-ce que tu peux (comprend: est-il sensé de)mettre dans une seule et même collection, des vertex qui ont un nombre de coordonnées différents
    En toute honnêteté, je répondrais que, de toute évidence, le nombre de coordonnées que les vertex manipulent va dépendre du référentiel utilisé par le contexte global de ton application:

    Soit tu travailles en "deux dimensions", et tous tes vertex seront composés de deux coordonnées, soit tu travailles en "trois dimensions", et tous tes vertex seront composés... de trois coordonnées.

    A priori, il n'y a pas plus de sens à placer un vertex composé de trois coordonnées dans un contexte "deux dimensions" qu'à placer un vertex composé de deux coordonnées dans un contexte... 3D !

    Ce n'est donc pas ton constructeur qui doit être template, mais carrément toute la classe

    Après, il y a plusieurs possibilités pour y arriver, l'une d'elles étant simplement de passer un paramètre de type entier pour indiquer le nombre de dimensions, par exemple sous une forme proche de
    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 <int d>
    class vertex
    {
        public:
            enum{dimension = d;}
            vertex():coordinates(new double[dimension]){}
            ~vertex(){delete coordinates;}
           /* ne pas oublier le constructeur par copie et l'opérateur d'affectation
            * que je passe ici ;)
            */
            double get(int num)const {return coordinates[num];}
            void set(int num, double value){coordinates[num] = value;}
        private:
            double * coordinates;
    };
    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

  5. #5
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut
    Bonjour, et merci pour vos réponses.

    En réalité, nous travaillons sur un programme de triangulation. Les coordonnées des points sont en trois dimensions puisque les triangles sont affichés en 3D via OpenGL. Cependant, la triangulation s'effectue dans le plan et ne requiert donc que les coordonnées (x,y); c'est pour cela que nous avons codé une série de fonctions template qui calculent la norme d'un vecteur, la distance entre deux vecteurs, etc. selon un certain nombre de coordonnées.

    Nous avons volontairement décidé d'écarter l'utilisation d'une classe template pour nous éviter d'avoir à nous soucier de la dimension complète d'un point. Ce que l'on veut, c'est pouvoir considérer un point 3D comme un point 2D en laissant "tomber" la dernière coordonnée qui correspond à la hauteur du point.

    Voici le code complet de la classe vertex réadaptée avec l'idée de Bousk.

    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
    class vertex
    {
    public:
    	/*
    	[Constructeur]
    	Il se contente d'attribuer le pointeur nul au pointeur des coordonnées.
    	*/
    	vertex() : dim(0), coordinates(nullptr)
    	{
    	}
     
    	/*
    	[Destructeur]
    	*/
    	~vertex(void)
    	{
    		/* libère la mémoire allouée au tableau des coordonnées du point */
    		if(coordinates != nullptr)
    			delete coordinates;
    	}
     
    	/*
    	Initialise l'objet vertex.
    	@param:		coordinates		les coordonnées du point
    	*/
    	template<size_t dim>
    	void init(double coordinates[dim])
    	{
    		if(dim < 1)
    			throw exception("vertex::init<size_t dim> : le paramètre dimensionnel est invalide.");
    		if(this->coordinates != nullptr)
    			delete coordinates;
     
    		this->dim = dim;
    		this->coordinates = new double[dim];
    		for(size_t i = 0; i < dim; ++i)
    			this->coordinates[i] = coordinates[i];
    	}
     
    	/*
    	Retourne les coordonnées du point dans un tableau pré-alloué.
    	@param:		coordinates		les coordonnées du point
    	*/
    	template<size_t dim>
    	void get_coordinates(double coordinates[dim]) const
    	{
    		if(this->coordinates == nullptr)
    			throw exception("vertex::get_coordinates<size_t dim> : l'objet n'a pas été initialisé (vertex::init<size_t dim>).");
    		if(dim > this->dim || dim < 0)
    			throw exception("vertex::get_coordinates<size_t dim> : le paramètre dimensionnel est invalide.");
    		for(size_t i = 0; i < dim; ++i)
    			coordinates[i] = this->coordinates[i];
    	}
     
    	/*
    	Modifie les coordonnées du point.
    	@param:		new_coordinates		les nouvelles coordonnées du point
    	*/
    	template<size_t dim>
    	void set_coordinates(double new_coordinates[dim])
    	{
    		if(this->coordinates == nullptr)
    			throw exception("vertex::set_coordinates<size_t dim> : l'objet n'a pas été initialisé (vertex::init<size_t dim>).");
    		if(dim > this->dim || dim < 0)
    			throw exception("vertex::set_coordinates<size_t dim> : le paramètre dimensionnel est invalide.");
    		for(size_t i = 0; i < dim; ++i)
    			this->coordinates[i] = coordinates[i];
    	}
    private:
    	size_t dim;
    	double * coordinates;
    };
    J'imagine que les utilisations de la classe exception et du keyword nullptr sont également discutables. :p

    Mais comme toujours, le tableau est rarement un bon choix. Je préfère de loin la paire d'itérateur.
    Pouvez-vous m'en dire davantage ?

    Bien à vous,

    Nicolas.

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Le gros problème d'un tableau, c'est qu'on ignore sa taille.

    C'est mal adapté à cette situation, mais en gros, ma proposition était de reprendre l'interface générale de la STL.
    Avec une paire d'itérateurs, directement tirés de <iterator>, vous aurez une indépendance vis à vis du conteneur utilisé par l'appeleur de votre constructeur.

    En gros ca permet d'avoir un appel en vertex v(truc.begin(), truc.end());.

    Cela dit, pour votre problème, il suffirait d'avoir des points 3D, et de ne lire que les deux premières dimensions…

  7. #7
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 149
    Billets dans le blog
    4
    Par défaut
    Je ne vois aucun avantage à ce choix par rapport à une simple structure Point avec 3 membres x,y,z, quitte à ne pas utiliser z dans certains algorithmes qui traitent le point en 2D.
    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.

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Nadd Voir le message
    Bonjour, et merci pour vos réponses.

    En réalité, nous travaillons sur un programme de triangulation. Les coordonnées des points sont en trois dimensions puisque les triangles sont affichés en 3D via OpenGL. Cependant, la triangulation s'effectue dans le plan et ne requiert donc que les coordonnées (x,y); c'est pour cela que nous avons codé une série de fonctions template qui calculent la norme d'un vecteur, la distance entre deux vecteurs, etc. selon un certain nombre de coordonnées.

    Nous avons volontairement décidé d'écarter l'utilisation d'une classe template pour nous éviter d'avoir à nous soucier de la dimension complète d'un point. Ce que l'on veut, c'est pouvoir considérer un point 3D comme un point 2D en laissant "tomber" la dernière coordonnée qui correspond à la hauteur du point.
    Cela n'a pas de sens...

    Tu peux, très facilement, envisager d'avoir une conversion de point 3D en point2D si tu n'as pas besoin d'une des coordonnées, mais le principe est strictement le même que lorsque tu travailles en système métrique et que tu veux avoir des informations en pouces, pieds, et miles : tu change de référentiel, et tu dois donc convertir tes valeurs

    La conversion peut, effectivement, se "contenter" d'ignorer la composante "Y", ou de la considérer comme ayant une valeur nulle, mais elle doit se faire

    Avec la classe template sous la forme que j'ai présentée, tu pourrais avoir deux fonctions proches de
    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
    vertex<2> to2D(vertex<3> const & origin)
    {
        vertex<2> ret;
        ret.set(0,origin.get(0));
        ret.set(1,origin.get(2));
        return ret;
    }
    vertex<3> to3D(vertex<2> const & origin)
    {
     
        vertex<3> ret;
        ret.set(0,origin.get(0));
        ret.set(2,origin.get(1));
        ret.set(1,origin.get(0.0));
        return ret;
    }
    Quand tu dois trianguler, tu convertis de la sorte tous tes plans et toutes tes droites, puis tu les manipule en "deux dimensions", pour terminer en convertissant le résultat en 3D en vue de l'affichage

    Ou bien, tu te bases sur le fait que, quoi qu'il arrive, tu travailles toujours avec des points "3D", mais que, quoi qu'il arrive, le résultat d'une triangulation aura toujours une valeur arbitraire pour la coordonnée Y, qui peut etre, au choix nulle ou équivalente à la moyenne de la coordonnée des coordonnées Y des points de référence(ou toute autre valeur valide mais arbitraire de ton choix).

    Dans ce cas, la classe vertex pourrait d'ailleurs ne plus être template
    Mais, quoi qu'il en soit, il n'y a strictement aucun sens à vouloir faire tenir des points 2D et des points 3D dans une seule et même collection
    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

  9. #9
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut
    La conversion peut, effectivement, se "contenter" d'ignorer la composante "Y", ou de la considérer comme ayant une valeur nulle, mais elle doit se faire.
    Imaginons que j'ai un point en 3D : vertex<3> *v. Si je le convertis en 2D pour effectuer la triangulation puis que je le reconvertis en 3D, je ne risque pas de perdre une composante ?

    Sinon, j'ai saisi l'incohérence d'avoir des points 2D et 3D dans une même collection.

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 26/02/2015, 01h20
  2. Prototype du constructeur d'une classe template
    Par Meseira dans le forum Langage
    Réponses: 11
    Dernier message: 05/01/2011, 08h47
  3. Réponses: 2
    Dernier message: 04/12/2005, 21h10
  4. Réponses: 5
    Dernier message: 20/11/2005, 11h15
  5. Réponses: 3
    Dernier message: 06/11/2005, 18h02

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