Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Définition d'un static const char**

7 réponses
Avatar
nico
Bonjour,

J'aimerais définir un tableau constant et static (j'ai essayé uniquement
constant avec une initialisation dans le constucteur et ca marche) :

class Classe1
{

static const char* mon_tbl[3];

};

const char * Classe1::mon_tbl[3] = { "e", "ee", "eee" };

mais avec ce code j'ai les erreurs de linkage suivantes :


main.obj : error LNK2005: "private: static char const * * Classe1::mon_tbl"
(?mon_tbl@Classe1@@0PAPBDA) déjà défini(e) dans FormComptaMain.obj
Classe1.obj : error LNK2005: "private: static char const * *
Classe1::mon_tbl" (?mon_tbl@Classe1@@0PAPBDA) déjà défini(e) dans
FormComptaMain.obj

Qu'est-ce qui ne va pas ?


Merci d'avance.

PS:Je ne suis pas sur de ma syntaxe const char * nom[x] car ce que je veux
c'est bien que les élements du tableaux soient constants.

--
nico

7 réponses

Avatar
kanze
nico wrote:

J'aimerais définir un tableau constant et static (j'ai essayé
uniquement constant avec une initialisation dans le
constucteur et ca marche) :

class Classe1
{
static const char* mon_tbl[3];
};

const char * Classe1::mon_tbl[3] = { "e", "ee", "eee" };

mais avec ce code j'ai les erreurs de linkage suivantes :

main.obj : error LNK2005: "private: static char const * *
Classe1::mon_tbl"

(?@@0PAPBDA) déjà défini(e) dans FormComptaMain.obj
Classe1.obj : error LNK2005: "private: static char const * *
Classe1::mon_tbl" (?@@0PAPBDA) déjà défini(e) dans
FormComptaMain.obj

Qu'est-ce qui ne va pas ?


A priori, tu as mis la définition dans le fichier d'en-tête. La
définition des éléments statiques fait partie de
l'implémentation, et doit se trouver dans le fichier source
(.cc, .cpp, etc.)) de la classe.

PS:Je ne suis pas sur de ma syntaxe const char * nom[x] car ce
que je veux c'est bien que les élements du tableaux soient
constants.


Pour que les éléments (les pointeurs) soient constant, il faut
déclarer :

static char const* const mon_tbl[ 3 ] ;

(Je suppose que tu veux que le texte pointé soit constante
aussi. Sinon, c'est :

static char *const mon_tbl[ 3 ] ;
)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
nico
Salut,

Ok merci je vais tester.
Sinon que signifie const char* ma_var ? (ie qu'est-ce qui est constant la
dedans).

--
nico

wrote:
nico wrote:

J'aimerais définir un tableau constant et static (j'ai essayé
uniquement constant avec une initialisation dans le
constucteur et ca marche) :

class Classe1
{
static const char* mon_tbl[3];
};

const char * Classe1::mon_tbl[3] = { "e", "ee", "eee" };

mais avec ce code j'ai les erreurs de linkage suivantes :

main.obj : error LNK2005: "private: static char const * *
Classe1::mon_tbl" (?@@0PAPBDA) déjà défini(e) dans
FormComptaMain.obj Classe1.obj : error LNK2005: "private: static
char const * * Classe1::mon_tbl" (?@@0PAPBDA) déjà
défini(e) dans FormComptaMain.obj

Qu'est-ce qui ne va pas ?


A priori, tu as mis la définition dans le fichier d'en-tête. La
définition des éléments statiques fait partie de
l'implémentation, et doit se trouver dans le fichier source
(.cc, .cpp, etc.)) de la classe.

PS:Je ne suis pas sur de ma syntaxe const char * nom[x] car ce
que je veux c'est bien que les élements du tableaux soient
constants.


Pour que les éléments (les pointeurs) soient constant, il faut
déclarer :

static char const* const mon_tbl[ 3 ] ;

(Je suppose que tu veux que le texte pointé soit constante
aussi. Sinon, c'est :

static char *const mon_tbl[ 3 ] ;
)



Avatar
Horst Kraemer
"nico" wrote:

Salut,

Ok merci je vais tester.
Sinon que signifie const char* ma_var ? (ie qu'est-ce qui est constant la
dedans).


Ce sont les caractères vers le quel ma_var pointe qui sont constants.

const char * tab[2] = { "aa", "bb" }

tab[0][0]='A' n'est donc pas permis. C'est la définition correcte si
tu initialise les pointeurs par des chaines litterales comme "ab"
parce qu'on n'a pas (selon la norme) le droit de changer une chaine
littérale.

Mais tu as le droit de changer les pointeurs après par une affectation
d'une nouvelle chaine littérale, p.ex.

tab[0] = "toto".

Si tu veux qu'on ne peut plus changer les pointeurs après
l'initialisation tu devrais déclarer

const char * const tab[2] = { "aa", "bb" };

Maintenant

tab[0] = "toto";

produirait une erreur.

--
Horst

--
Lâche pas la patate!

Avatar
kanze
nico wrote:

Sinon que signifie const char* ma_var ? (ie qu'est-ce qui est
constant la dedans).


Les char. C'est la même chose que « char const* ma_var ; ».

Dans la plupart des contextes, le const doit suivre ce qu'il
modifie, donc *const, c'est le pointeur qui est const, et
()const, c'est la fonction qui est const. Exceptionnellement, si
le const s'applique au premier élément de la déclaration, il
peut aussi précéder. Mais il peut aussi suivre. Certains
préfèrent le mettre derrière, même dans ce contexte, par souci
d'homogénéité, et la compréhénsion dans le cas des typedef.

Dans le cas des tableaux de type C, il y a aussi la règle qu'il
n'y a pas de tableaux const ; s'il y a un const qui s'applique
au tableau, on le transfère aux éléments.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
nico
dans ca cas pour un tabelau de char totalement constant (pointeurs et
élements) on aurait ca

(dite moi si j'ai rien compris :) )

const char* ma_var[3] const;
équivalent à
char const * ma_var[3] const;

et non

const char* const ma_var[3];
équivalent à
char const * const ma_var[3];

c'est bon ?

ou alors

char const * const ma_var[3] const;

merci en tout cas.

--
nico

wrote:
nico wrote:

Sinon que signifie const char* ma_var ? (ie qu'est-ce qui est
constant la dedans).


Les char. C'est la même chose que « char const* ma_var ; ».

Dans la plupart des contextes, le const doit suivre ce qu'il
modifie, donc *const, c'est le pointeur qui est const, et
()const, c'est la fonction qui est const. Exceptionnellement, si
le const s'applique au premier élément de la déclaration, il
peut aussi précéder. Mais il peut aussi suivre. Certains
préfèrent le mettre derrière, même dans ce contexte, par souci
d'homogénéité, et la compréhénsion dans le cas des typedef.

Dans le cas des tableaux de type C, il y a aussi la règle qu'il
n'y a pas de tableaux const ; s'il y a un const qui s'applique
au tableau, on le transfère aux éléments.



Avatar
kanze
nico wrote:
dans ca cas pour un tabelau de char totalement constant
(pointeurs et élements) on aurait ca


Un tableau n'est jamais const. (Ne me démande pas pourquoi.
C'est comme ça, et en C++ et en C.) Et pour un tableau de char
totalement const, il suffit :

char const tableau[ N ] ;

Mais je crois que tu parles en fait d'un tableau de pointeurs
vers char où et les pointeurs et les char sont const.

(dite moi si j'ai rien compris :) )

const char* ma_var[3] const;
équivalent à
char const * ma_var[3] const;


Non. Le tableau ne peut pas être déclaré const. Les pointeurs
si :

char const * const tableau[ N ] ;

En ce qui concerne les tableaux const : le const derrière un []
etant illégal, il n'y a pas de syntaxe qui le permet
directement, mais on pourrait apparamment y arriver au moyen des
typedef :

typedef char MonTableau[ N ] ;
MonTableau const maVar ;

Seulement, il y a une règle spéciale : « Any cv-qualifiers
applied to an array type affect the array element type, not the
array type. » Donc, la déclaration ci-dessus n'équivaut pas
l'impossible :
char maVar[ N ] const ;
mais :
char const maVar[ N ] ;

Note bien aussi ce qui est le type de l'élément. Dans :
typedef char* MonTableau[ N ] ;
MonTableau const var ;
ce sont bien les pointeurs, et non les char, qui sont const,
parce que le type des éléments du tableau, c'est pointeur.

C'est d'ailleurs l'argument le plus fort pour la
post-positionnement systèmatique du const :

typedef char* PtrChar ;
PtrChar const p1 ;
const PtrChar p2 ;

Dans les deux cas, le const s'applique au type définit par le
typedef, c-à-d le pointeur. Dans le premier cas, ça semble assez
évident, parce que si on remplace le typedef par son expansion :
char * const p1 ;
c'est ce qui se passe. Le deuxième cas est trompeur, parce que
l'expansion ne met pas le const où il faut :
const char * p2 ;
ne lui correspond pas.

Si tu te sers de std::vector, tout rentre dans l'ordre, plus ou
moins :

std::vector< char const * > v1 ;
// tableau non-const de pointeur non-const de char const
std::vector< char * const > v2 ;
// tableau non-const de pointeur const de char non-const
const std::vector< char * > v3 ;
// tableau const de pointeur non-const de char non-const

Plus ou moins, parce que :
1. le deuxième est illégal -- tu ne peux pas avoir un vector
d'éléments const, parce qu'on ne peut pas affecter à un
élément const, et
2. toutes les fonctions qui permettrait de modifier un élément
d'un vector sont non-const, ce qui fait que sans tricher
avec const_cast, tu ne peux pas modifier les pointeurs dans
la troisième version.

En fait, on revient un peu à la règle des tableaux C -- la
const-ité du tableau devient la const-ité des éléments. À peu
près parce que dans le cas de vector, il y a bien aussi un sens
de const-ité pour le vector -- tu ne peux pas ajouter ni
supprimer d'éléments d'un vector const, et aussi parce que le
contenu du vecteur sont bien des objets non-const, et que les
modifier au moyen d'un const_cast est légal et défini, à
l'encontre du cas avec les tableaux de type C. (En fait, quand
je veux que tout soit const, et a fortiori quand je veux que
l'initialisation soit statique, je me sers encore des tableaux
de type C.)

Enfin, j'espère que cette explication peut-être trop détaillée
n'a pas apporté plus de confusion que les lumières.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
nico
Salut,

Super merci c'est très clair.

--
nico

wrote:
nico wrote:
dans ca cas pour un tabelau de char totalement constant
(pointeurs et élements) on aurait ca


Un tableau n'est jamais const. (Ne me démande pas pourquoi.
C'est comme ça, et en C++ et en C.) Et pour un tableau de char
totalement const, il suffit :

char const tableau[ N ] ;

Mais je crois que tu parles en fait d'un tableau de pointeurs
vers char où et les pointeurs et les char sont const.

(dite moi si j'ai rien compris :) )

const char* ma_var[3] const;
équivalent à
char const * ma_var[3] const;


Non. Le tableau ne peut pas être déclaré const. Les pointeurs
si :

char const * const tableau[ N ] ;

En ce qui concerne les tableaux const : le const derrière un []
etant illégal, il n'y a pas de syntaxe qui le permet
directement, mais on pourrait apparamment y arriver au moyen des
typedef :

typedef char MonTableau[ N ] ;
MonTableau const maVar ;

Seulement, il y a une règle spéciale : « Any cv-qualifiers
applied to an array type affect the array element type, not the
array type. » Donc, la déclaration ci-dessus n'équivaut pas
l'impossible :
char maVar[ N ] const ;
mais :
char const maVar[ N ] ;

Note bien aussi ce qui est le type de l'élément. Dans :
typedef char* MonTableau[ N ] ;
MonTableau const var ;
ce sont bien les pointeurs, et non les char, qui sont const,
parce que le type des éléments du tableau, c'est pointeur.

C'est d'ailleurs l'argument le plus fort pour la
post-positionnement systèmatique du const :

typedef char* PtrChar ;
PtrChar const p1 ;
const PtrChar p2 ;

Dans les deux cas, le const s'applique au type définit par le
typedef, c-à-d le pointeur. Dans le premier cas, ça semble assez
évident, parce que si on remplace le typedef par son expansion :
char * const p1 ;
c'est ce qui se passe. Le deuxième cas est trompeur, parce que
l'expansion ne met pas le const où il faut :
const char * p2 ;
ne lui correspond pas.

Si tu te sers de std::vector, tout rentre dans l'ordre, plus ou
moins :

std::vector< char const * > v1 ;
// tableau non-const de pointeur non-const de char const
std::vector< char * const > v2 ;
// tableau non-const de pointeur const de char non-const
const std::vector< char * > v3 ;
// tableau const de pointeur non-const de char non-const

Plus ou moins, parce que :
1. le deuxième est illégal -- tu ne peux pas avoir un vector
d'éléments const, parce qu'on ne peut pas affecter à un
élément const, et
2. toutes les fonctions qui permettrait de modifier un élément
d'un vector sont non-const, ce qui fait que sans tricher
avec const_cast, tu ne peux pas modifier les pointeurs dans
la troisième version.

En fait, on revient un peu à la règle des tableaux C -- la
const-ité du tableau devient la const-ité des éléments. À peu
près parce que dans le cas de vector, il y a bien aussi un sens
de const-ité pour le vector -- tu ne peux pas ajouter ni
supprimer d'éléments d'un vector const, et aussi parce que le
contenu du vecteur sont bien des objets non-const, et que les
modifier au moyen d'un const_cast est légal et défini, à
l'encontre du cas avec les tableaux de type C. (En fait, quand
je veux que tout soit const, et a fortiori quand je veux que
l'initialisation soit statique, je me sers encore des tableaux
de type C.)

Enfin, j'espère que cette explication peut-être trop détaillée
n'a pas apporté plus de confusion que les lumières.