OVH Cloud OVH Cloud

Question entretien C++ - doutes.

95 réponses
Avatar
David Fleury
Bonjour,

voici une des questions que je pose pour lors de mes entretiens pour des
développeurs avec expérience orienté C++

"Ecrire une fonction qui renverse une chaine (ex: ABC -> CBA, AE -> EA, ...)

Après avoir posé la question deux ou trois fois déjà, je suis surpris
des réponses (souvent fausses). Je laisse volontairement le choix au
candidat d'utiliser (char* ou std::string) et/ou une fonction modifiant
la chaine entrée ou retournant une nouvelle chaine, et l'utilisation de
la STL est autorisé.

A votre avis, est-ce que la question n'est pas trop mauvaise ?

David.

PS : Dans le même genre, il y a la fonction EstPalindrome qui semble
bloquer.

10 réponses

Avatar
ld
On 30 oct, 15:02, Michael DOUBEZ wrote:
ld a écrit :

> On 30 oct, 10:37, James Kanze wrote:
>> On Oct 30, 8:41 am, ld wrote:

>>> On 28 oct, 19:13, David Fleury wrote:
>>     [...]

>>> En particulier avec C++, la capacite a faire un bon design est
>>> essentielle dans un "vrai" projet.
>> Ce n'est pas particulier avec C++ ; une bonne conception est
>> essentielle, quelque soit le langage.

> Je considère que c'est encore plus critique sur les langages
> statiquement typés avec peu/pas de fonctionnalités dynamiques comme C
> et C++ et où le manque de flexibilité du design se paye au prix for t.

C'est d'autant plus vrai pour les langages dynamiques où il est
nécessaire d'avoir une bonne couverture de test et où l'architecture est
pressurés par la testabilité.



Je ne suis pas non plus un fan des languages dynamiques. Mais il y a
des solutions intermediaires. Je suis pas pro Java ou C# non plus,
mais sur ce point la il font mieux (compte tenu de leur capacite, tout
est relatif). L'ideal pour moi etant COS: statique dans les classes,
dynamique en dehors, simplicite et efficacite partout ;-)

> Le minimum étant les interfaces à-la-Java que malheureusement C++ n 'a
> pas (mais pourrait).

Quel est le problème avec les classes virtuelles pures ?

struct IConnectable
{
   virtual connect()=0;
   virtual disconnect()=0;
};

Je dirai plutôt que c'est Java qui n'a pas voulu des héritages multip les.



Il y en a plusieurs:

Les instances contiendront (n+1) pointeurs vers les multiples vtbls
pour n heritage multiples, meme si ses classes abstraites de base
n'ont pas de donnees membres (interfaces). Le modele objet de C++
pourrait optimiser ca, mais c'est assez complique a cause d'une part
du "vrai" heritage multiple et d'autre part des contraintes dans les
ctors/dtors. En tout cas gcc ne le fait pas. Donc si la classe
implemente ± 10 interfaces, un cas assez courant pour un design
"flexible", on se retrouve avec 5 a 10 pointeurs dans les instances
(je suppose quelques heritages simples dans le tas). Ces pointeurs
necessitent des ajustements d'offsets dans l'instance a chaque fois
que l'on utilise l'instance a travers une de ses interfaces (ce qui
est le but pour la flexibilite), et ce qui demande de generer du code
et des calculs en plus. De plus il faut utiliser au maximum les
retours contravariant pour garder un maximum de visibilite statique,
ce qui demande aussi des ajustements d'offset, ceci afin de minimiser
les dynamic_cast qui sont tres lents (bien plus qu'un double
dispatch). Tous ces offsets varient suivant le contexte et se trouvent
dans les multiples vtbls de la classe, donc mouvements de cache,
indirections, etc. Le compilateur a peu de marge pour optimiser tout
ca lorsqu'on utilise l'instance a travers ses interfaces (ce qui est
le but, mais je l'ai deja dit ;-). Enfin, en theorie, il faudrait
deriver virtuellement *par defaut* pour un design flexible sans "bombe
a retardement", mais cela rajoute encore des pointeurs des des
ajustements d'offset. Au final tous ces calculs intermediaires
ralentissent la resolution des appels virtuels de facon non
negligeable. Mes mesures sur gcc 4.2 montrent que par rapport a un
appel virtuel avec heritage simple, l'heritage multiple de 4
interfaces ralentit d'un facteur ±2 l'appel, et l'heritage virtuel
d'un facteur ±4. Soit ±8 au total si on mixe les deux, ce qui serait
l'approche correcte. Je ne pense pas que les autres compilateur font
mieux et je trouve deja pas mal compte tenu de tout ce que le
compilateur doit generer. La faute au "vrai" heritage multiple.

Maintenant de mon point de vue, qui n'engage que moi, je trouverais
beaucoup plus utile une implementation tres efficace des interfaces a-
la-Java en C++ (space & time) a la place de l'heritage multiple
rarement utile et facilement simulable quand on a vraiment besoin.
C'est aussi le choix de C# et de D si je ne me trompe pas.

>> Mais la question reste :
>> quelle est la poste à pourvoir ? Dans des grandes équipes, il y
>> a beaucoup de programmeurs qui n'ont qu'à implémenter des
>> éléments d'une conception qui leur est donnée. (Dans un projet,
>> au moins, environ 80% des développeurs n'avaient même pas le
>> droit de toucher aux fichiers d'en-tête. Qui était de toute
>> façon générée à partir du modèle par Rational Rose.)

> Tout à fait d'accord. Mais comme je n'ai jamais travaillé dans une
> "grande" équipe (>20) et comme je crois que c'est somme toute assez
> rare, je n'avais pas considéré ce cas de figure. Autant pour moi. C eci-
> dit, je n'aime les projets où on considère les programmeurs comme d es
> générateurs de code et où leur rôle est ultra spécialisé. M on coté
> créatif sans doute ;-)

Ça dépends de la taille du projet. Typiquement, il y a un groupe de
développeur qui est là du début à la fin (core team) et d'autres qui
viennent en renfort à certains points clés de la vie du projet (en
général au milieu). Ceux qui viennent aider ne sont pas moins créat ifs
même si il est peut probable qu'ils prennent une décision qui va
influencer le cours du projet.



N'etant programmeur professionnel mon experience sur ce sujet est tres
succinte. Je suis donc a l'ecoute et ca me parait coherent.

a+, ld.
Avatar
ld
On 30 oct, 10:04, James Kanze wrote:
Et c'est bien plus difficile d'évaluer sa capacité de travailler
en équipe ou de communiquer qu'il ne l'est d'évaluer ses
compétences C++. Alors qu'à la rigueur, le C++ s'apprend, tandis
que la capacité de travailler en équipe et de communiquer
clairement ses idées, plus difficilement.



"ce qui se conçoit bien s’énonce clairement et les mots pour le dire
viennent aisément" donc pour ce qui est des questions relative au C++,
cela peu poser des problèmes de communication de ne pas le comprendre.
Imagine toi assister à une réunion en Mandarin (à moins que tu ne le
parles?), il te sera difficile de participer...

Je ne sais pas. La dernière fois que j'avais à valider les
compétences des candidats, je trouveais que 9 sur 10 s'heurter
sur des questions aussi simple que « Pourquoi est-ce qu'on
déclarerait un destructeur virtuel ? ».



Parce que le compilateur le demande ;-)

Un (avec soi-disant 2
ans d'expérience avec C++ dans un projet OO) m'a même démandé ce
que j'entendais par « virtuel ».



Arf, recalé.

a+, ld.
Avatar
Wykaaa
Michael DOUBEZ a écrit :
ld a écrit :
On 30 oct, 10:37, James Kanze wrote:
On Oct 30, 8:41 am, ld wrote:

On 28 oct, 19:13, David Fleury wrote:


[...]

En particulier avec C++, la capacite a faire un bon design est
essentielle dans un "vrai" projet.


Ce n'est pas particulier avec C++ ; une bonne conception est
essentielle, quelque soit le langage.







Absolument. La phase de programmation ne doit être que la mise en oeuvre
stricte de la conception.
C'est pourquoi on ne devrait pas demander à un programmeur d'être
créatif mais de maîtriser parfaitement (j'insiste sur le parfaitement)
le(s) langage(s) dans le(s)quel(s) il programme.
Dans un monde de développement idéal, le programmeur doit être le garant
que la sémantique de l'application, décrite par le dossier fonctionnel
et la conception, est respecté dans sa transcription à l'aide d'un
langage sur la machine.

Je considère que c'est encore plus critique sur les langages
statiquement typés avec peu/pas de fonctionnalités dynamiques comme C
et C++ et où le manque de flexibilité du design se paye au prix fort.



C'est d'autant plus vrai pour les langages dynamiques où il est
nécessaire d'avoir une bonne couverture de test et où l'architecture est
pressurés par la testabilité.


Dans les applications industrielles et, en particulier, temps réel les
différentes phases de tests peuvent représenter jusqu'à 60% du total
des hommes.mois du projet.
Au passage, la couverture de test ne fait pas tout, hélas. Une
couverture C1 à 100% ne garantit absolument pas l'absence de défaut...

Le minimum étant les interfaces à-la-Java que malheureusement C++ n'a
pas (mais pourrait).





Les interfaces sont les "contrats" des différents modules. Les
interfaces doivent comprendre les pré et post conditions sur
l'utilisations des différentes fonctions des interfaces. Je ne comprends
toujours pas, qu'au bout de plus de 20 ans, C++ ne possède pas la notion
d'interface. Les classes abstraites peuvent jouer partiellement ce rôle
mais c'est en trichant avec cet idiome.

Quel est le problème avec les classes virtuelles pures ?

struct IConnectable
{
virtual connect()=0;
virtual disconnect()=0;
};

Je dirai plutôt que c'est Java qui n'a pas voulu des héritages multiples.



Heureusement. L'héritage multiple (en C++, en particulier) est une
hérésie. Java n'a pas voulu retomber dans ces travers et on comprend
pourquoi car avec l'héritage multiple on peut avoir plusieurs chemins
d'héritage, d'où la notion de dérivation virtuelle et des avatars que
cela engendre...
Pour répondre à la question avec les classes virtuelles pures, le
problème c'est que je ne suis pas sûr qu'elles le restent. Rien
n'interdit de faire une classe dérivée de cette classe en ajoutant des
méthodes qui ne seront pas virtuelles pures et en laissant les autres
non définies.
Au moins, en Java, même si j'ai l'héritage d'interface, je suis garantis
que tant que je dis interface, il n'ya aucune implémentation d'aucune
méthode et quand je dis qu'une classe "implements" une ou des interface,
je dois définir (coder) toutes les méthodes spécifiées de toutes les
interfaces. C'est donc beaucoup plus propre.
De plus, en Java, je peux déclarer qu'une classe est "final" ce qui
interdit de faire des sous-classes. Cela manque beaucoup en C++.


Mais la question reste :
quelle est la poste à pourvoir ? Dans des grandes équipes, il y
a beaucoup de programmeurs qui n'ont qu'à implémenter des
éléments d'une conception qui leur est donnée. (Dans un projet,
au moins, environ 80% des développeurs n'avaient même pas le
droit de toucher aux fichiers d'en-tête. Qui était de toute
façon générée à partir du modèle par Rational Rose.)



Tout à fait d'accord. Mais comme je n'ai jamais travaillé dans une
"grande" équipe (>20) et comme je crois que c'est somme toute assez
rare, je n'avais pas considéré ce cas de figure. Autant pour moi. Ceci-
dit, je n'aime les projets où on considère les programmeurs comme des
générateurs de code et où leur rôle est ultra spécialisé. Mon coté
créatif sans doute ;-)



Ça dépends de la taille du projet. Typiquement, il y a un groupe de
développeur qui est là du début à la fin (core team) et d'autres qui
viennent en renfort à certains points clés de la vie du projet (en
général au milieu). Ceux qui viennent aider ne sont pas moins créatifs
même si il est peut probable qu'ils prennent une décision qui va
influencer le cours du projet.



J'ai connu deux projets énormes (environ 4 millions de lignes de C++
chacun) dans lesquels, au bout de 6 ans, il n'y avait plus aucun membre
de l'équipe d'origine (chefs de projets, concepteurs, développeurs,
testeurs, intégrateurs, administrateurs, etc.) car la règle de mobilité
imposait qu'une personne ne reste pas plus de 4 ans au même endroit !
L'avantage c'est qu'il y avait des docs absolument complètes et à jour
(ce qui est extrêmement rare dans la vie courante des projets
informatiques).
Les développeurs n'avaient aucune latitude par rapport à la conception.
Ils n'avaient pas le droit de créer une classe qui ne figurait pas dans
la conception ni de rajouter des méthodes !
Avatar
Wykaaa
Michael DOUBEZ a écrit :
Wykaaa a écrit :
[snip]
Je voulais dire, en fait :
pt étant un nom de tableau peut-on écrire pt++ ?
La réponse est évidemment non puisqu'un nom de tableau est un pointeur
constant sur le premier élément du tableau.



Comme d'autre l'ont signalé, le om d'un tableau est de type tableau et
non pas de type pointer. Pour des raisons historiques (K&R C), le
tableau se converti implicitement en pointeur mais il reste un tableau.

D'ailleur:
int * const ptr;
const int tab[42];
int * const ptr=tab;

sizeoff(ptr)!=sizeof(tab)



Mais tab[5] == *(tab+5)
Donc ta dernière phrase joue sur les mots car, dans la partie droite de
ma comparaison, le nom du tableau est bien utilisé comme un pointeur !
Et là c'est encore plus fort car tab+5 signifie :
&tab[0] + 5*sizeof(type_des_elements_du_tableau).

C'est bien ce qui trouble nombre de débutants en C/C++ (et même quelques
fois, des non débutants, ces espèces d'équivalences pointeurs/tableau.

D'ailleurs on peut écrire : "0123456789ABCDEF"[i].
Je peux te garantir que ceci trouble même certains programmeurs C très
expérimentés.
Avatar
James Kanze
On Oct 30, 4:31 pm, ld wrote:
On 30 oct, 10:04, James Kanze wrote:



> Et c'est bien plus difficile d'évaluer sa capacité de
> travailler en équipe ou de communiquer qu'il ne l'est
> d'évaluer ses compétences C++. Alors qu'à la rigueur, le C++
> s'apprend, tandis que la capacité de travailler en équipe et
> de communiquer clairement ses idées, plus difficilement.



"ce qui se conçoit bien s?énonce clairement et les mots pour
le dire viennent aisément" donc pour ce qui est des questions
relative au C++, cela peu poser des problèmes de communication
de ne pas le comprendre.



Il y a effectivement un rapport. Ceux qui conçoivent bien
peuvent toujours s'exprimer clairement et avec précision ; ceux
qui conçoivent mal rarement.

Maintenant, je ne suis pas sûr d'avoir bien compris. Est-ce qui
tu veux suggérer que la conception du C++ n'est pas très bien,
et que donc, c'est difficile à en parler de façon claire et avec
précision ? :-)

Imagine toi assister à une réunion en Mandarin (à moins que tu
ne le parles?), il te sera difficile de participer...



Certes, mais pour une poste en France, je m'attendrais qu'on
discute soit en français, soit en anglais (dans le contexte d'un
projet international). Ou sinon qu'une connaissance de Mandarin
soit exigée d'avance, dans quel cas, je ne me postulerais même
pas. Mais je ne vois pas trop le rapport avec des compétences
C++.

> Je ne sais pas. La dernière fois que j'avais à valider les
> compétences des candidats, je trouveais que 9 sur 10
> s'heurter sur des questions aussi simple que « Pourquoi
> est-ce qu'on déclarerait un destructeur virtuel ? ».



Parce que le compilateur le demande ;-)



Justement non. Le compilateur ne le démande pas. La réponse
exacte comportera obligatoirement des mots « comportement
indéfin ». Mais j'acceptais aussi des réponses à peu près
correctes.

> Un (avec soi-disant 2 ans d'expérience avec C++ dans un
> projet OO) m'a même démandé ce que j'entendais par
> « virtuel ».



Arf, recalé.



Justement, non. J'ai bien signalé mon avis (que le candidat
était complétement incompétant, et qu'il mentait sur le CV),
mais on m'a répondu qu'il nous fallait quand même quelques uns,
et que vu le marché à l'époque, on n'en trouverait pas d'autres.

J'ai commencé peu après à chercher un autre projet:-).

--
James Kanze (GABI Software) email:
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
James Kanze
On Oct 30, 2:30 pm, ld wrote:
On 30 oct, 10:37, James Kanze wrote:



> On Oct 30, 8:41 am, ld wrote:



> > On 28 oct, 19:13, David Fleury wrote:



> [...]



> > En particulier avec C++, la capacite a faire un bon design
> > est essentielle dans un "vrai" projet.



> Ce n'est pas particulier avec C++ ; une bonne conception est
> essentielle, quelque soit le langage.



Je considère que c'est encore plus critique sur les langages
statiquement typés avec peu/pas de fonctionnalités dynamiques
comme C et C++ et où le manque de flexibilité du design se
paye au prix fort.



D'après mon expérience, c'est exactement le contraire. La
conception, il te le faut, de toute façon. La différence, c'est
qu'avec des langages statiquement typés, comme le C++, une
partie de la conception (la partie la plus basse) est vérifiée
par le compilateur, et s'exprime dans le langage directement.

Le minimum étant les interfaces à-la-Java que malheureusement
C++ n'a pas (mais pourrait).



Comment ça ? Je m'en sers tous les jours en C++. Le problème,
en fait, c'est que Java ne supporte pas très bien la conception
d'interfaces avec contrat.

> Mais la question reste :
> quelle est la poste à pourvoir ? Dans des grandes équipes,
> il y a beaucoup de programmeurs qui n'ont qu'à implémenter
> des éléments d'une conception qui leur est donnée. (Dans un
> projet, au moins, environ 80% des développeurs n'avaient
> même pas le droit de toucher aux fichiers d'en-tête. Qui
> était de toute façon générée à partir du modèle par Ratio nal
> Rose.)



Tout à fait d'accord. Mais comme je n'ai jamais travaillé dans
une "grande" équipe (>20) et comme je crois que c'est somme
toute assez rare,



Et pourtant, je ai rarement travaillé autrement. (Chez T Mobil,
où j'étais avant, j'étais seul sur ma partie du projet, pendant
un moment. Mais c'est bien une exception.)

je n'avais pas considéré ce cas de figure. Autant pour moi.
Ceci- dit, je n'aime les projets où on considère les
programmeurs comme des générateurs de code et où leur rôle est
ultra spécialisé. Mon coté créatif sans doute ;-)



Tout dépend. Moi non plus, je ne prendrais pas de poste où je
n'avais qu'à « pisser la ligne ». À commencer parce que ça ne
payerait certainement pas assez. Mais tout le monde n'a pas les
mêmes exigeances, ni la même expérience. Dans la pratique, les
gens assez compétents pour s'occuper de la conception sont
rares. Tu ne veux pas qu'ils perdent leur temps à coder ce que
pourrait être codé par des gens bien moins compétents, plus
facile à trouver, et moins payés. Et si tu considères un projet
complet, il faut bien dire que la plupart de travail n'exige pas
un niveau très élevé. Moi, je préfère travailler sur de grands
projets bien gérés, parce que là, justement, il y a des autres
pour faire tout ce travail ennuyeux, et que je peux me
concentrer uniquement sur les parties qui posent un certain
défi (et qui sont donc plus intéressantes).

--
James Kanze (GABI Software) email:
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
James Kanze
On Oct 30, 3:02 pm, Michael DOUBEZ wrote:
ld a écrit :



> On 30 oct, 10:37, James Kanze wrote:
>> On Oct 30, 8:41 am, ld wrote:



>>> On 28 oct, 19:13, David Fleury wrote:
>> [...]



>>> En particulier avec C++, la capacite a faire un bon design
>>> est essentielle dans un "vrai" projet.
>> Ce n'est pas particulier avec C++ ; une bonne conception
>> est essentielle, quelque soit le langage.



> Je considère que c'est encore plus critique sur les langages
> statiquement typés avec peu/pas de fonctionnalités
> dynamiques comme C et C++ et où le manque de flexibilité du
> design se paye au prix fort.



C'est d'autant plus vrai pour les langages dynamiques où il
est nécessaire d'avoir une bonne couverture de test et où
l'architecture est pressurés par la testabilité.



> Le minimum étant les interfaces à-la-Java que
> malheureusement C++ n'a pas (mais pourrait).



Quel est le problème avec les classes virtuelles pures ?



struct IConnectable
{
virtual connect()=0;
virtual disconnect()=0;
};



Le problème, c'est que tu ne peux pas vérifier le contrat. Dans
les cas où il n'y a pas de contrat (les inversions d'appel, par
exemple), c'est bien, mais dans les autres, en général, l'idiome
consacré est plutôt :

class Connectable
{
public
void connect()
{
// vérifier les préconditions...
doConnect() ;
// vérifier les postconditions...
}

private:
virtual void doConnect() = 0 ;
} ;

Une interface qui impose un contrat doit avoir du code, qu'il
soit généré implicitement (comme en Eiffel) ou explicitement
(comme en C++).

Je dirai plutôt que c'est Java qui n'a pas voulu des héritages
multiples.



Dans le cas des interfaces, si. Ce qu'il n'a pas voulu, c'est
l'enforcement des contrats. Donc, de vraies interfaces typées.

--
James Kanze (GABI Software) email:
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
ld
On 30 oct, 17:59, James Kanze wrote:
> "ce qui se conçoit bien s?énonce clairement et les mots pour
> le dire viennent aisément" donc pour ce qui est des questions
> relative au C++, cela peu poser des problèmes de communication
> de ne pas le comprendre.

Il y a effectivement un rapport. Ceux qui conçoivent bien
peuvent toujours s'exprimer clairement et avec précision ; ceux
qui conçoivent mal rarement.

Maintenant, je ne suis pas sûr d'avoir bien compris. Est-ce qui
tu veux suggérer que la conception du C++ n'est pas très bien,
et que donc, c'est difficile à en parler de façon claire et avec
précision ? :-)



Je ne m'aventurerais pas sur ce terrain...

> Imagine toi assister à une réunion en Mandarin (à moins que tu
> ne le parles?), il te sera difficile de participer...

Certes, mais pour une poste en France, je m'attendrais qu'on
discute soit en français, soit en anglais (dans le contexte d'un
projet international). Ou sinon qu'une connaissance de Mandarin
soit exigée d'avance, dans quel cas, je ne me postulerais même
pas. Mais je ne vois pas trop le rapport avec des compétences
C++.



C'est que si il ne comprend pas le C++, une discussion technique aura
l'air d'etre du chinois pour lui et sa participation proche de zero.

J'ai eu le cas recemment ou on etait une quinzaine de personnes et au
cours de la discussion, un dialogue s'est installe entre une personne
du groupe et moi et les autres commencaient a s'endormir. Un peu gene
apres qques minutes, j'ai "reouvert" le sujet pour que tout le monde
participe.

> > Je ne sais pas. La dernière fois que j'avais à valider les
> > compétences des candidats, je trouveais que 9 sur 10
> > s'heurter sur des questions aussi simple que « Pourquoi
> > est-ce qu'on déclarerait un destructeur virtuel ? ».
> Parce que le compilateur le demande ;-)

Justement non. Le compilateur ne le démande pas.



gcc le demande des que ta classe definit un type polymorphique.

La réponse
exacte comportera obligatoirement des mots « comportement
indéfin ». Mais j'acceptais aussi des réponses à peu près
correctes.



Entendre des mots comme "pure virtual call" ou "memory leak" ou
quelques mots sur la nature monomorphique de ::delete serait evidement
un plus ;-)


> > Un (avec soi-disant 2 ans d'expérience avec C++ dans un
> > projet OO) m'a même démandé ce que j'entendais par
> > « virtuel ».
> Arf, recalé.

Justement, non. J'ai bien signalé mon avis (que le candidat
était complétement incompétant, et qu'il mentait sur le CV),
mais on m'a répondu qu'il nous fallait quand même quelques uns,
et que vu le marché à l'époque, on n'en trouverait pas d'autres.

J'ai commencé peu après à chercher un autre projet:-).



Et tu as bien fait ;-)

a+, ld.
Avatar
Olivier Miakinen
Le 30/10/2008 17:55, Wykaaa a écrit :

C'est bien ce qui trouble nombre de débutants en C/C++ (et même quelques
fois, des non débutants, ces espèces d'équivalences pointeurs/tableau.

D'ailleurs on peut écrire : "0123456789ABCDEF"[i].



On peut même écrire : i["0123456789ABCDEF"] !

Je peux te garantir que ceci trouble même certains programmeurs C très
expérimentés.



Cette toute dernière façon de faire est en effet assez troublante.
Avatar
James Kanze
On Oct 30, 4:15 pm, ld wrote:
On 30 oct, 15:02, Michael DOUBEZ wrote:
> ld a écrit :



> > Le minimum étant les interfaces à-la-Java que
> > malheureusement C++ n'a pas (mais pourrait).



> Quel est le problème avec les classes virtuelles pures ?



> struct IConnectable
> {
> virtual connect()=0;
> virtual disconnect()=0;
> };



> Je dirai plutôt que c'est Java qui n'a pas voulu des
> héritages multiples.



Il y en a plusieurs:



Les instances contiendront (n+1) pointeurs vers les multiples
vtbls pour n heritage multiples, meme si ses classes
abstraites de base n'ont pas de donnees membres (interfaces).
Le modele objet de C++ pourrait optimiser ca, mais c'est assez
complique a cause d'une part du "vrai" heritage multiple et
d'autre part des contraintes dans les ctors/dtors. En tout cas
gcc ne le fait pas. Donc si la classe implemente ± 10
interfaces, un cas assez courant pour un design "flexible", on
se retrouve avec 5 a 10 pointeurs dans les instances (je
suppose quelques heritages simples dans le tas). Ces pointeurs
necessitent des ajustements d'offsets dans l'instance a chaque
fois que l'on utilise l'instance a travers une de ses
interfaces (ce qui est le but pour la flexibilite), et ce qui
demande de generer du code et des calculs en plus.



Et alors ? Mieux vaut que ce soit le compilateur qui s'en
occupe, et pas toi, non ? Et si tu as une classe qui implémente
plusieurs interfaces, quel est l'alternatif ? Sans l'héritage
multiple, tu es bien obligé d'y introduire autant de
passerelles. Donc, des objets supplémentaires, avec leur vptr,
etc., un niveau d'indirection en plus, ET qui sont écrit par
toi, donc beaucoup plus de travail (et plus de possibilités
d'erreur).

De plus il faut utiliser au maximum les retours contravariant
pour garder un maximum de visibilite statique,



L'utilisation d'un retour contravariant est en général une
indication d'une mauvaise conception, ou peut-être plutôt une
paresse dans la définition de l'interface. À éviter.

Enfin, en theorie, il faudrait deriver virtuellement *par
defaut* pour un design flexible sans "bombe a retardement",



Dans le cas où une interface étend une autre, absolument. C'est
une règle de programmation à ne pas effreindre. Il serait bien
préférable que l'héritage virtuel soit le défaut, parce qu'il
marche dans prèsque tous les cas. Mais il n'est pas essentiel
quand on hérite afin d'implémenter, plutôt que pour étendre
l'interface, parce qu'à ce moment là, au moins d'utiliser un
idiome comme le modèle de template (« template method
pattern » en anglais -- rien à voir avec les templates C++),
on sait qu'on a affaire à la classe la plus dérivée, et donc que
l'héritage virtuel n'est pas nécessaire.

mais cela rajoute encore des pointeurs des des ajustements
d'offset. Au final tous ces calculs intermediaires
ralentissent la resolution des appels virtuels de facon non
negligeable. Mes mesures sur gcc 4.2 montrent que par rapport
a un appel virtuel avec heritage simple, l'heritage multiple
de 4 interfaces ralentit d'un facteur ±2 l'appel, et
l'heritage virtuel d'un facteur ±4. Soit ±8 au total si on
mixe les deux, ce qui serait l'approche correcte. Je ne pense
pas que les autres compilateur font mieux et je trouve deja
pas mal compte tenu de tout ce que le compilateur doit
generer.



Et alors ? Est-ce que tu connais des applications où ça fait
une différence ? Je me suis servi parfois des graphes
d'héritage à peine croyable (à cause des contraints techniques
liés à la façon qu'on générait le code), et ça n'a jamais eu un
impact mesurable sur les performances de l'application.

La faute au "vrai" heritage multiple.



Et qu'est-ce que tu appelles un « vrai » héritage multiple ?
Et comment est-ce qu'il est implémenté ?

Maintenant de mon point de vue, qui n'engage que moi, je
trouverais beaucoup plus utile une implementation tres
efficace des interfaces a- la-Java en C++ (space & time) a la
place de l'heritage multiple rarement utile et facilement
simulable quand on a vraiment besoin.



Quand tu utilises l'héritage multiple en Java, ça fonctionne
plus ou moins comme l'héritage multiple en C++. De point de vue
pratique, quand tu « extend » une interface, c'est exactement
comme si tu héritais virtuellement de la classe en C++.

--
James Kanze (GABI Software) email:
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