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

Classe "implicite" d'un itérateur

24 réponses
Avatar
Dominique MICOLLET
Bonjour

J'ai un doute dans ma compréhension de la déclaration d'un itérateur dans la
situation suivante :

class A : public vector <B>
{
......
void C();
}

void A:C()
{
....
const_iterator I=begin(); //cbegin() en C++11
.....
}

Suis-je dans l'erreur en considérant que I est implicitement déclaré comme
A::const_iterator I et qu'il équivaut à un vector<B>::const_iterator ?

Cordialement
Dominique

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
Dominique MICOLLET writes:

Bonjour,

Jean-Marc Bourguet wrote:

Entre auto et hériter publiquement d'une classe comme vector<> qui n'a
pas été conçue pour, je sais ce que je préfèrer ais qu'on enseigne à ceux
qui voudraient devenir mes collègues. ;-)



Rassurez-vous, je n'enseigne pas le C++ :-).

Plus sérieusement, pourriez-vous développer votre réticenc e quant à
l'héritage public de vector ?



Les cas où c'est sensé sont l'exception plutôt que la rà ¨gle. En
général, l'héritage public concerne les classes entité (pas copiable,
présence de fonctions virtuelles) et pas les classes valeur (copiable,
absence de fonctions virtuelles). vector est clairement dans la seconde
catégorie.

L'héritage public de classes valeur est généralement un hà ©ritage de
convenance, de facilité, pas un héritage qui résulte de crit ères de
conception. La question de fond est de savoir quelles sont les
invariants que la classe peut bien avoir qu'il n'est pas possible de
mettre à mal en la manipulant comme un vecteur? Si des invariants sont
à risque, l'héritage public est clairement une mauvaise idée . Si aucun
invariant est à risque, on se demande ce que la classe apporte
(complèter une API perçue comme incomplète en ignorant le ri sque de
faire une classe n'a pas une responsabilité claire est la raison la pl us
valable).

L'exemple classique de problèmes introduits par l'héritage public de
classes sans destructeur virtuel est bien sûr la possibilité de f aire

classe_de_base* p = new classe_derivee;
delete p;

qui est du comportement indéfini. Il convint mal, les classes valeur
n'étant normalement pas gérées comme ça, l'argument per d en poids ce
qu'il a gagné en étant applicable systématiquement. Quand o n connait
les classes, construire des cas plus pertinents est généralement
possible, et quand ce n'est pas le cas, on est dans les cas
exceptionnels où l'héritage est sensé.

Craindre auto me fait penser aux programmeurs C qui craignent les
paramètres références non constantes.



Je n'ai pas compris.



Il y a des programmeurs C qui trouvent qu'en C++

void f(int& p) { ... modifie p ... }

n'est pas assez explicite et donc font

void f(int* p) { ... modifie *p ... }

Eviter auto parce que pas assez explicite me rappelle ces programmeurs.

Etre explicite ou pas est une question interessante, et que certains
tranchent un peu vite, dans les deux sens. Condamner d'office quelque
chose sans l'avoir experimente reellement, parce que pas assez explicite
me semble aussi nuisible que condamner d'office quelque chose parce que
trop explicite (j'en connais habitués à d'autres langages).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Jean-Marc Bourguet
Dominique MICOLLET writes:

Bonjour,

Jean-Marc Bourguet wrote:
Plus précisément I est explicitement déclaré comme étant du type
const_iterator trouvé
par une recherche dans le contexte courant. On va chercher dans A::C(),
il n'y a probablement rien, on va chercher dans A, il n'y a probablement
rien, on va chercher dans vector<B>, il y a probablement quelque chose.



C'est bien comme cela que je le préssentais.


Considérer qu'il y a un const_iterator déclaré implicitem ent déclaré
dans A fonctionne assez bien, mais décrit aussi peu la réalit é
que de considérer qu'il y en a un implicitement déclaré d ans A::C. Ça
fonctionne jusqu'au moment où on se trouve dans un cas où la r echerche
s'arrête plus tôt (dans les templates par exemple), et celui q ui a ce
modèle dans la tête ne comprend plus ce qui se passe.



Je ne comprends pas votre remarque.



Je chipote sur la nuance entre "I est implicitement déclaré comme
A::const_iterator I et équivaut à un vector<B>::const_iterator" et
"const_iterator est trouvé en effectuant une recherche dans le contexte
courant, recherche qui elle même remonte dans la hiérarchie".

J'ignore bien sûr s'il est dans "vector" ou encore plus loin dans la
hiérarchie



Il est des cas où la recherche ne remonte pas dans la hiérarchie et donc
ne peut pas trouver le const_iterator de vector. Les templates par
exemple. Ou bien dans le cas des fonctions, en trouver une à un niveau
va masquer les autres, même si elles conviendraient mieux.

Exemple avec un namespace (on peut faire avec deux classes A et B
héritant de A, je le montre avec des namespaces parce qu'on montre
généralement le problème avec des classes et que certains en concluent
incorrectement qu'il est lié aux classes)

namespace A {
void f(int) { std::cout << "A::f(int)n"; }
namespace B {
void f(double) { std::cout << "A::B::f(double)n"; }
void g() { f(42); }
}
}
int main() {
A::B::g();
}

affiche

A::B::f(double)

tandis qu'ajouter un

using A::f;

dans B permet d'afficher

A::f(int)

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Lucas Levrel
Le 6 mars 2015, Jean-Marc Bourguet a écrit :

Les cas où c'est sensé sont l'exception plutôt que la règle. En
général, l'héritage public concerne les classes entité (pas copiable,
présence de fonctions virtuelles) et pas les classes valeur (copiable,
absence de fonctions virtuelles). vector est clairement dans la seconde
catégorie.



Peux-tu donner un exemple de classe entité ?

La question de fond est de savoir quelles sont les
invariants que la classe peut bien avoir qu'il n'est pas possible de
mettre à mal en la manipulant comme un vecteur?



Pas compris. Peux-tu détailler ?

(complèter une API perçue comme incomplète en ignorant le risque de
faire une classe n'a pas une responsabilité claire est la raison la plus
valable).



Syntax error :-)

--
LL
Ἕν οἶδα ὅτι οὐδὲν οἶδα (Σωκράτης)
Avatar
Lucas Levrel
Le 6 mars 2015, Dominique MICOLLET a écrit :

Par ailleurs, je "potasse" en ce moment :
http://www.icce.rug.nl/documents/cplusplus/
C'est un cours dont le début est très prometteur.



Merci pour cette référence.

--
LL
Ἕν οἶδα ὅτι οὐδὲν οἶδα (Σωκράτης)
Avatar
Jean-Marc Bourguet
Lucas Levrel writes:

Le 6 mars 2015, Jean-Marc Bourguet a écrit :

Les cas où c'est sensé sont l'exception plutôt que la r ègle. En
général, l'héritage public concerne les classes entità © (pas copiable,
présence de fonctions virtuelles) et pas les classes valeur (copiab le,
absence de fonctions virtuelles). vector est clairement dans la seconde
catégorie.



Peux-tu donner un exemple de classe entité ?



std::streambuf

La question de fond est de savoir quelles sont les invariants que la
classe peut bien avoir qu'il n'est pas possible de mettre à mal en la
manipulant comme un vecteur?



Pas compris. Peux-tu détailler ?



Si tu fais une classe vecteur_trie qui herite publiquement de vector et
qui essaie de faire en sorte de garder le vecteur trie, le fait que tu
peux acceder a la classe de base va te permettre de casser l'invariant
(le fait que le vecteur est trie)


(complèter une API perçue comme incomplète en ignorant le risque de
faire une classe n'a pas une responsabilité claire est la raison la plus
valable).



Syntax error :-)



Un principe de conception est qu'une classe doit avoir une
responsabilité claire et restreinte (certains disent meme unique --
personnellement j'ai un probleme de savoir ce qui est unique et ne l'est
pas). Completer l'API obscurcit souvent la responsabilite n'est pas
claire l'elargit (exemple de chose à ne pas faire, les classes string de
la SL ou de Qt font beaucoup trop de choses qui a mon avis ne relevent
pas de la responsabilite d'une classe mais devraient etre faites par des
fonctions libres).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
espie
En complement, et de facon bien moins technique: l'heritage public est LA
relation la plus forte qui peut exister entre deux classes. Il faut se
poser la question: si la classe de base change, est-ce qu'on veut heriter
de tout le nouveau comportement ? Si ce n'est pas le cas, c'est que
l'heritage public est une mauvaise idee, et qu'il faudrait utiliser un
autre schema (composition ou delegation le plus souvent).

Je sais que ca peut paraitre bizarre, pour vector, qui est dans la norme
et qui donc "change" peu (meme si il y a plein de trucs cools en C++2011)
mais c'est la vraie question a se poser...

A la base, l'objet c'est surtout cense permettre d'isoler l'utilisateur
final de changements intempestifs dans l'implementation. Et l'heritage
public "garantit" que l'utilisateur final va se palucher les changements
ET dans la classe derivee, ET dans la classe de base... c'est en meme temps
tres puissant et tres intrusif.

Perso, je n'herite plus guere que d'interfaces au sens java, des classes
qui ne contiennent que le comportement que je veux, et rien cote
implementation...
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Perso, je n'herite plus guere que d'interfaces au sens java, des classes
qui ne contiennent que le comportement que je veux, et rien cote
implementation...



Ça peut être difficile si on n'a pas écrit toutes les libs q u'ont
utilise. (Je pense à Qt p.e.)

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
(Marc Espie) writes:

Perso, je n'herite plus guere que d'interfaces au sens java, des classes
qui ne contiennent que le comportement que je veux, et rien cote
implementation...



Ça peut être difficile si on n'a pas écrit toutes les libs qu'ont
utilise. (Je pense à Qt p.e.)



Ouaip. Bien sur sur mon propre design.

Je trouve que Qt s'en sort pas trop mal, ils ont un design qu'est quand meme
un poil date ces jours-ci, mais qui marche encore relativement bien avec
du C++14...
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

In article ,
Jean-Marc Bourguet wrote:
(Marc Espie) writes:

Perso, je n'herite plus guere que d'interfaces au sens java, des classes
qui ne contiennent que le comportement que je veux, et rien cote
implementation...



Ça peut être difficile si on n'a pas écrit toutes les libs qu'ont
utilise. (Je pense à Qt p.e.)



Ouaip. Bien sur sur mon propre design.

Je trouve que Qt s'en sort pas trop mal, ils ont un design qu'est quand meme
un poil date ces jours-ci, mais qui marche encore relativement bien avec
du C++14...



C'est daté, mais pas insupportable. Le pire, c'est moc et l'idée d'une
classe dont (presque) tout hérite, et le fait qu'ils ont une approche
framework plutôt que lib et donc une certaine tendance à tout lier.

A+

--
Jean-Marc
FAQ de fclc++: http://web.archive.org/web/*/http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Lucas Levrel
Le 6 mars 2015, Jean-Marc Bourguet a écrit :

Completer l'API obscurcit souvent la responsabilite n'est pas
claire l'elargit



Trois verbes à la suite, j'ai un problème d'analyse syntaxique de cette
phrase :-)

(exemple de chose à ne pas faire, les classes string de la SL [...] font
beaucoup trop de choses qui a mon avis ne relevent pas de la
responsabilite d'une classe mais devraient etre faites par des fonctions
libres).



Est-ce que tu fais allusion aux fonctions copy, find, compare, substr de
la STL ?

--
LL
Ἕν οἶδα ὅτι οὐδὲν οἶδα (Σωκράτης)
1 2 3