2008-11-06 8 views
8

Si je fais ceci:C question de const

// In header 
class Foo { 
void foo(bar*); 
}; 

// In cpp 
void Foo::foo(bar* const pBar) { 
//Stuff 
} 

Le compilateur ne se plaint pas que les signatures pour Foo :: foo ne correspondent pas. Toutefois, si j'avais:

void foo(const bar*); //In header 
void Foo::foo(bar*) {} //In cpp 

Le code ne pourra pas être compilé.

Que se passe-t-il? J'utilise gcc 4.1.x

+0

Voulez-vous dire mettre le const de l'autre côté du * dans votre deuxième exemple? Certaines personnes répondent en expliquant la différence dans la signification de cela, et d'autres répondent en expliquant la différence dans le fait que le const est dans le fichier cpp ou le fichier h. –

+0

Vous devriez choisir une aswer à votre question ou mettre à jour si ce n'est pas la réponse que vous cherchez. –

Répondre

1

Le mot-clé const dans le premier exemple n'a pas de sens. Vous dites que vous ne prévoyez pas de changer le pointeur. Cependant, le pointeur a été passé par valeur et donc cela n'a pas d'importance si vous le modifiez ou non; cela n'affectera pas l'appelant. De même, vous pouvez aussi le faire:

// In header 
class Foo { 
void foo(int b); 
}; 

// In cpp 
void Foo::foo(const int b) { 
//Stuff 
} 

Vous pouvez même le faire:

// In header 
class Foo { 
void foo(const int b); 
}; 

// In cpp 
void Foo::foo(int b) { 
//Stuff 
} 

Depuis le int est passé par valeur, le constness n'a pas d'importance.

Dans le deuxième exemple, vous dites que votre fonction prend un pointeur sur un type, mais l'implémente comme un pointeur sur un autre type, donc il échoue.

15

Dans la première, vous avez promis le compilateur, mais pas les autres utilisateurs de la classe que vous ne modifierez pas la variable.

Dans votre deuxième exemple, vous avez promis d'autres utilisateurs de la classe que vous ne modifieront pas leur variable, mais n'a pas respecté cette promesse.

Il faut aussi noter qu'il ya une nette différence entre

bar* const variable 

et

const bar* variable 

et

const bar* const variable 

Dans la première forme, le pointeur ne changera jamais, mais vous pouvez éditer l'objet pointé. Dans la deuxième forme, vous pouvez éditer le pointeur (pointer vers un autre objet), mais jamais la variable vers laquelle il pointe. Dans la forme finale, vous ne modifierez pas le pointeur, ni l'objet vers lequel il pointe. Reference

Pour ajouter un peu plus d'une précision à la question posée, vous pouvez toujours promettre plus que moins const. Étant donné une classe:

class Foo { 
    void func1 (int x); 
    void func2 (int *x); 
} 

Vous pouvez compiler la mise en œuvre suivante:

Foo::func1(const int x) {} 
Foo::func2(const int *x) {} 

ou:

Foo::func1(const int x) {} 
Foo::func2(const int* const x) {} 

sans aucun problème. Vous avez indiqué à vos utilisateurs que vous pouvez éventuellement modifier leurs variables. Dans votre implémentation, vous avez dit au compilateur que cette implémentation particulière n'éditerait pas ces variables, même si cela était indiqué aux utilisateurs. Vous n'avez pas rompu une promesse à l'utilisateur, et donc le code compile.

+0

Je ne pense pas que votre théorie soit valable: 1) Si vous déclarez "int *" et implémentez "const int *", comme dans votre exemple, il ne compile pas. 2) Si vous passez par valeur, vous pouvez déclarer const et ne pas implémenter avec const. Cela n'a pas de sens lorsque vous passez en valeur. –

+0

oui. Je suis d'accord que vous avez tort. void f (int const *); est différent de void f (int *); Je pense que vous vouliez écrire void f (int * const); a la même signature que void f (int *); vous devriez changer votre exemple car il pourrait confondre les débutants. –

0

Dans le premier, l'const n'affecte pas l'interface, seule la mise en œuvre. Vous dites au compilateur, « Je ne vais pas changer la valeur de la bar* au sein de cette fonction ». Vous pouvez toujours changer ce qui est pointé par le pointeur. Dans ce dernier, vous dites au compilateur (et tous les appelants) que vous ne changerez pas la structure bar que les bar*points.

+0

Je pense que vous voulez dire dans la dernière phrase "vous ne modifierez pas la barre que la barre * indique". "Changer la barre de points" pourrait signifier "donner une nouvelle valeur à la barre", ce qui est bien sûr le cas dans le deuxième exemple. –

+0

Merci pour cela, corrigé. Les pronoms sont le fléau de la clarté. –

6

Voir this question, this question et this question.

Fondamentalement, le const signifie seulement que la fonction ne modifiera pas la valeur du pointeur. Le contenu des pointeurs n'est pas const, identique à la signature de l'en-tête.

0

Ainsi, le deuxième const:

void Foo::foo(const bar* const); 

est pas partie de la signature de la méthode?

+1

Vous déclarez une méthode dans le fichier .h, vous le définissez dans le fichier .cpp.Tout dans la déclaration fait partie de la signature (les deux consts), il apparaît que dans la définition, vous pouvez affiner le type d'argument de façon plus précise tant que cette définition ne casse pas la sémantique de la déclaration. –

+0

@mamin: Correct. Par exemple, regardez l'erreur de l'éditeur de liens que vous obtenez si vous déclarez (mais ne définissez pas) une fonction "void foo (const int * const a)", puis l'appelez. La signature signalée par GCC est "foo (int const *)". –

+0

simple: si vous ajoutez/supprimez const il ne fera pas partie de la signature. donc void foo (int * const); et void foo (int *); ont en effet la même signature. MAIS void foo (int const *); et void foo (int *); ont des signatures différentes: il n'y a pas de const ajouté au type de paramètre, mais au type pointé. –

0

Ceci est plus simple à comprendre avec un type de variable autre qu'un pointeur. Par exemple, vous pouvez avoir la déclaration de fonction suivante:

void foo(int i); 

La définition peut ressembler à ceci:

void foo(const int i) { ... } 

si la variable « i » est const ou non du côté de la définition est un détail de mise en œuvre . Cela n'a aucun impact pour les clients de cette fonction.

+0

Je ne comprends pas comment les utilisateurs SO votent. top voté avec +15 ci-dessus est une réponse qui a une fausse déclaration à la fin et n'a pas envie de la corriger (ppl lui a dit ça il y a 3 mois), et à -1 cette réponse est-elle correcte et bien mieux expliquée (A MON HUMBLE AVIS). faire +1 pour des raisons d'équité. –

+0

D'accord. Je ne comprends pas pourquoi j'ai été downvoted pour cette réponse ... –

0

Il ne se soucie probablement pas beaucoup de void Foo::foo(bar* const pBar) parce que la façon dont vous traitez le pointeur lui-même (const ou non) n'a pas d'importance un bit en dehors de la routine. Les règles C indiquent qu'aucun changement de pBar ne se fera en dehors de foo. Cependant, s'il s'agit de (const bar* pBar), cela fait une différence, car cela signifie que le compilateur ne doit pas permettre aux appelants de passer dans des pointeurs vers des objets non const.