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

Redefinition de l'operateur []

5 réponses
Avatar
Eric Jacoboni
Bonjour,

Après avoir fouillé dans pas mal de docs, je n'ai toujours pas trouvé
de réponse à un problème "apparemment simple" :

Je prend un exemple soumis par un collègue, auquel je n'ai pas su
répondre :

Soit une classe Vecteur_Creux sensée représenter un vecteur creux. On
veut redefinir [] de sorte qu'on puisse accéder assez naturellement à
un élément par son "indice" ou que l'élément indicé puisse servir de
lvalue.

Le "problème" est qu'il faudrait pouvoir distinguer le cas où cet
opérateur est appelé "en lecture" et le cas où il l'est en écriture
car le traitement n'est pas le même dans les deux cas (coup classique
des vecteurs creux lors de l'affectation d'un élément, notamment).

Je ne sais pas si je me fais bien comprendre, donc je prend un exemple
avec un autre langage où, là, je sais faire :

def [](indice)
# appelée par une instruction comme "if machin[10]" ou
# "truc = machin[2]"
end

def []=(indice)
# appelée par une instruction comme "machin[10] = 12"
end

Il reste bien sur l'option consistant à définir deux méthodes portant
des noms comme get ou set... Le problème n'est pas tant d'y arriver
que de de savoir s'il y a une solution avec une redéfinition de [].


--
Eric Jacoboni, ne il y a 1442696510 secondes

5 réponses

Avatar
Franck Branjonneau
Eric Jacoboni écrivait:

Soit une classe Vecteur_Creux sensée représenter un vecteur creux. On
veut redefinir [] de sorte qu'on puisse accéder assez naturellement à
un élément par son "indice" ou que l'élément indicé puisse servir de
lvalue.

Le "problème" est qu'il faudrait pouvoir distinguer le cas où cet
opérateur est appelé "en lecture" et le cas où il l'est en écriture
car le traitement n'est pas le même dans les deux cas (coup classique
des vecteurs creux lors de l'affectation d'un élément, notamment).


operator[](int) et operator[](int) const ne conviennent pas ?

--
Franck Branjonneau

Avatar
Loïc Joly
Bonjour,

Après avoir fouillé dans pas mal de docs, je n'ai toujours pas trouvé
de réponse à un problème "apparemment simple" :

Je prend un exemple soumis par un collègue, auquel je n'ai pas su
répondre :

Soit une classe Vecteur_Creux sensée représenter un vecteur creux. On
veut redefinir [] de sorte qu'on puisse accéder assez naturellement à
un élément par son "indice" ou que l'élément indicé puisse servir de
lvalue.

Le "problème" est qu'il faudrait pouvoir distinguer le cas où cet
opérateur est appelé "en lecture" et le cas où il l'est en écriture
car le traitement n'est pas le même dans les deux cas (coup classique
des vecteurs creux lors de l'affectation d'un élément, notamment).


Il n'est pas possible de différentier directement lecture ou écriture
avec l'opérateur []. Par contre, en ajoutant le célèbre niveau
d'indirection supplémentaire...

Tu fais retourner à ton opérateur [] non pas un double, mais une classe.
Cette classe retiens en mémoire le vecteur creux et l'indice
correspondant à ce qui a été demandé. Cette classe se comporte
globalement comme un double, mais par contre, affecter une valeur à
cette classe lui fait appeler la fonction qui va bien du vecteur creux.

--
Loïc

Avatar
Loïc Joly
Eric Jacoboni écrivait:


Soit une classe Vecteur_Creux sensée représenter un vecteur creux. On
veut redefinir [] de sorte qu'on puisse accéder assez naturellement à
un élément par son "indice" ou que l'élément indicé puisse servir de
lvalue.

Le "problème" est qu'il faudrait pouvoir distinguer le cas où cet
opérateur est appelé "en lecture" et le cas où il l'est en écriture
car le traitement n'est pas le même dans les deux cas (coup classique
des vecteurs creux lors de l'affectation d'un élément, notamment).



operator[](int) et operator[](int) const ne conviennent pas ?


On peut très bien vouloir accèder en lecture à un conteneur non constant.

--
Loïc


Avatar
Eric Jacoboni
Loïc Joly writes:

Il n'est pas possible de différentier directement lecture ou écriture
avec l'opérateur []. Par contre, en ajoutant le célèbre niveau
d'indirection supplémentaire...


Ah, donc cela confirme mes supputations.

Tu fais retourner à ton opérateur [] non pas un double, mais une
classe. Cette classe retiens en mémoire le vecteur creux et l'indice
correspondant à ce qui a été demandé. Cette classe se comporte
globalement comme un double, mais par contre, affecter une valeur à
cette classe lui fait appeler la fonction qui va bien du vecteur
creux.


Ok, merci. Je vais transmettre ça à l'intéressé.

--
Eric Jacoboni, ne il y a 1442703458 secondes

Avatar
kanze
Loïc Joly wrote:

Après avoir fouillé dans pas mal de docs, je n'ai toujours
pas trouvé de réponse à un problème "apparemment simple" :

Je prend un exemple soumis par un collègue, auquel je n'ai
pas su répondre :

Soit une classe Vecteur_Creux sensée représenter un vecteur
creux. On veut redefinir [] de sorte qu'on puisse accéder
assez naturellement à un élément par son "indice" ou que
l'élément indicé puisse servir de lvalue.

Le "problème" est qu'il faudrait pouvoir distinguer le cas
où cet opérateur est appelé "en lecture" et le cas où il
l'est en écriture car le traitement n'est pas le même dans
les deux cas (coup classique des vecteurs creux lors de
l'affectation d'un élément, notamment).


Il n'est pas possible de différentier directement lecture ou
écriture avec l'opérateur []. Par contre, en ajoutant le
célèbre niveau d'indirection supplémentaire...

Tu fais retourner à ton opérateur [] non pas un double, mais
une classe. Cette classe retiens en mémoire le vecteur creux
et l'indice correspondant à ce qui a été demandé. Cette classe
se comporte globalement comme un double, mais par contre,
affecter une valeur à cette classe lui fait appeler la
fonction qui va bien du vecteur creux.


C'est classe s'appelle un proxy, et son utilisation, comme
décrit ici, est le modèle de proxy.

En fait, pour être plus clair : on utilise un opérateur de
conversion implicit (« operator double() const ») pour la
conversion en rvalue. En revanche, il faut bien fournir tous les
opérations lvalue -- la classe aurait donc un
« operator=(double) const » pour l'affectation. (Et oui,
l'opérateur d'affectation est const, parce qu'il ne change pas
l'état de l'objet -- qui n'est qu'un proxy -- mais celui du
vecteur.)

Pour double, selon le cas, on pourrait aussi vouloir fournir les
opérateurs du genre +=, -=, etc., de façon à pouvoir écrire
« v[i] += 2.5 ».

Pour les objets de type classe, c'est plus délicat. Une des
opérations prémordial sur un lvalue de type classe, c'est .,
e.g. lvalue.f(). Et on ne peut pas surcharger l'opérateur ..

--
James Kanze GABI Software
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