OVH Cloud OVH Cloud

Traduire en C++ ?

44 réponses
Avatar
Pierre Maurette
Bonjour,
J'ai quelques petites fonctions C90, dont je souhaite réutiliser le
code source, éventuellement légèrement modifié (donc pas de mise en
bib).
Faisant largement appel à stdio.h elles sont tout sauf "idiomatiques"
en C++, mais elles sont parfaitement (hum, je l'espère en tous cas)
conformes à la norme de ce langage. Je précise que l'interface
elle-même est C plus que C++. Un exemple:

int AjouteNumLignes(const char nom_in[]
,const char nom_out[]
,const int nbr_caracts
);

Le int de retour est sémantiquement un bool.
Réécririez-vous ces fonctions en vue d'une utilisation en C++, sachant
qu'elles ont été validées par l'usage dans leur version actuelle ?
Quelle serait la raison objective de cette réécriture ?
Pour l'instant, je pense qu'il est possible de réutiliser "as is" ces
fonctions. Eventuellement en modifiant l'interface:

bool AjouteNumLignesCPP(const std::string nom_in
,const std::string nom_out
,const int nbr_caracts
)
{
return (AjouteNumLignesC(nom_in.c_str()
,nom_out.c_str()
,nbr_caracts) != 0);
}

Merci pour vos lumières.
--
Pierre

10 réponses

1 2 3 4 5
Avatar
Fabien LE LEZ
On Tue, 31 Aug 2004 09:36:02 +0200, Pierre Maurette
:

Pour l'instant, je pense qu'il est possible de réutiliser "as is" ces
fonctions. Eventuellement en modifiant l'interface:


Yep, c'est effectivement la méthode généralement adoptée, du moins
tant que tu n'as pas de modifications importantes à faire dans le code
d'origine.
Note que souvent, on va plus loin : on fait des classes (quand ça a un
sens effectivement), dont les membres appellent les fonctions
d'origine. Le cas typique qui se prête bien à une encapsulation dans
une classe :

struct truc { ... };
machin* open_truc (...);
int lire_un_octet_dans_truc (truc*, ...);
void ecrire_un_octet_dans_truc (truc*, ...);
void fermer_un_truc (truc*);

Le int de retour est sémantiquement un bool.


Vérifie-le bien -- je connais un OS, très utilisé sur les PC, dont
l'API contient un "BOOL" qui a trois états :-/

|BOOL GetMessage(...
|Return Values:
|If the function retrieves a message other than WM_QUIT, the return value is nonzero.
|If the function retrieves the WM_QUIT message, the return value is zero.
|If there is an error, the return value is -1.
(sic)

bool AjouteNumLignesCPP(const std::string nom_in


N'aurais-tu pas oublié un "&" ?

bool AjouteNumLignesCPP(const std::string &nom_in

--
;-)

Avatar
Pierre Maurette
Fabien LE LEZ a écrit:

On Tue, 31 Aug 2004 09:36:02 +0200, Pierre Maurette
:

Pour l'instant, je pense qu'il est possible de réutiliser "as is" ces
fonctions. Eventuellement en modifiant l'interface:


Yep, c'est effectivement la méthode généralement adoptée, du moins
tant que tu n'as pas de modifications importantes à faire dans le code
d'origine.
Note que souvent, on va plus loin : on fait des classes (quand ça a un
sens effectivement), dont les membres appellent les fonctions
d'origine. Le cas typique qui se prête bien à une encapsulation dans
une classe :

struct truc { ... };
machin* open_truc (...);
int lire_un_octet_dans_truc (truc*, ...);
void ecrire_un_octet_dans_truc (truc*, ...);
void fermer_un_truc (truc*);

Le int de retour est sémantiquement un bool.


Vérifie-le bien -- je connais un OS, très utilisé sur les PC, dont
l'API contient un "BOOL" qui a trois états :-/

|BOOL GetMessage(...
|Return Values:
|If the function retrieves a message other than WM_QUIT, the return value is nonzero.
|If the function retrieves the WM_QUIT message, the return value is zero.
|If there is an error, the return value is -1.
(sic)
Je me souviens avoir utilisé cet exemple (sur fclc ou fclc++) pour

présenter la notion de pseudo-booléens. Les réactions de la communauté
furent fraîches, si j'ai bonne mémoire ;-)

Ici, et sur cet exemple précis, c'est un presque bool, puisqu'il ne
renvoie que EXIT_SUCCESS ou EXIT_FAILURE que je réutilise tel quel.
Disons que c'est un enum à deux membres.

bool AjouteNumLignesCPP(const std::string nom_in


N'aurais-tu pas oublié un "&" ?

bool AjouteNumLignesCPP(const std::string &nom_in
Le passage par référence est ici indispensable ?

Je pensais que le compilateur de démerdait, qu'il était capable de
décider lui-même de résoudre le passage par valeur d'un objet constant
par un pointeur. Me gourre-je ?
--
Pierre


Avatar
Fabien LE LEZ
On Tue, 31 Aug 2004 11:05:40 +0200, Pierre Maurette
:

[31 lignes de citation]


Argh ! Abrège un peu !
N'hésite pas à ne citer que ce qui est vraiment indispensable à la
compréhension de ce que tu écris. Au-delà de quatre lignes
consécutives de citation, tu dois te poser la question.

Ici, et sur cet exemple précis, c'est un presque bool, puisqu'il ne
renvoie que EXIT_SUCCESS ou EXIT_FAILURE que je réutilise tel quel.


Dans ce cas, écris plutôt

return AjouteNumLignesCPP (...) == EXIT_SUCCESS;

bool AjouteNumLignesCPP(const std::string &nom_in
Le passage par référence est ici indispensable ?

Je pensais que le compilateur de démerdait, qu'il était capable de
décider lui-même de résoudre le passage par valeur d'un objet constant
par un pointeur.


J'ai de gros doutes sur la capacité du compilateur à optimiser ça.
Mais de toutes façons, la solution canonique pour passer un objet en
paramètre est la référence constante. Si tu fais autre chose, tu écris
explicitement que tu as un besoin particulier, que tu es hors du cas
normal -- donc tu pousses le lecteur à se demander pourquoi.


--
;-)


Avatar
Pierre Maurette
Fabien LE LEZ a écrit:
[...]
Argh ! Abrège un peu !
OK. Je coupe en grand le plus souvent, là je n'avais pas osé (!)

tailler dans votre prose ...

[...]
J'ai de gros doutes sur la capacité du compilateur à optimiser ça.
Mais de toutes façons, la solution canonique pour passer un objet en
paramètre est la référence constante. Si tu fais autre chose, tu écris
explicitement que tu as un besoin particulier, que tu es hors du cas
normal -- donc tu pousses le lecteur à se demander pourquoi.
Well, well. C'est clair.

Ce qui est con, c'est que le but est de passer un const char*, ce
qu'on faisait très bien sans rien toucher ;-).
Je me demande parfois si on n'a pas tendance à se tripoter un peu le
kiki avec les idiomes et autres canonismes.
Et si AjouteNumLignes() est une méthode, serait-il admissible de
conserver les char*, étant entendu que ce sont des propriétés private?
--
Pierre

Avatar
Fabien LE LEZ
On Tue, 31 Aug 2004 15:34:11 +0200, Pierre Maurette
:

Ce qui est con, c'est que le but est de passer un const char*


Passe un "const char*" si tu veux. Mais pas un "std::string" par
valeur.

Et si AjouteNumLignes() est une méthode,


Une fonction membre, tu veux dire ?

serait-il admissible de
conserver les char*, étant entendu que ce sont des propriétés private?


Franchement, je n'ai rien du tout contre les "char const*". Les
"char*" tout court, par contre, posent beaucoup plus problème.


--
;-)

Avatar
Andre Heinen
On Tue, 31 Aug 2004 09:36:02 +0200, Pierre Maurette
wrote:

J'ai quelques petites fonctions C90, <snip>
Réécririez-vous ces fonctions en vue d'une utilisation en C++, sachant
qu'elles ont été validées par l'usage dans leur version actuelle ?


Non, si ça marche il vaut mieux ne pas y toucher. Il vaut même
mieux ne pas les recopier dans un fichier C++, puisque ce n'est
pas exactement le même langage. Le mieux est AMHA de les laisser
dans un fichier C, compilé séparément.

Quelle serait la raison objective de cette réécriture ?


C'est à toi de nous le dire. S'il y a une bonne raison de faire
le changement, fais-le; par exemple si une réécriture rendrait
leur utilisation beaucoup plus aisée. Mais si ça convient comme
ça, toute modification est du travail supplémentaire inutile.
Avec en prime le risque d'ajouter un bug.

<snip>


--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"

Avatar
Andre Heinen
On Tue, 31 Aug 2004 11:05:40 +0200, Pierre Maurette
wrote:
bool AjouteNumLignesCPP(const std::string &nom_in
Le passage par référence est ici indispensable ?



Soit la fonction
void f(MaClasse monInstance);

Le passage par référence est indispensable:
1) si MaClasse n'a pas de constructeur de copie public,
2) si on veut pouvoir appeler f() en lui passant un objet d'une
classe dérivée de MaClasse en évitant le slicing et en permettant
l'emploi des fonctions virtuelles (polymorphisme, quoi...),
3) si la copie de MaClasse est catastrophiquement lente.

Dans le cas de std::string, avec une bibliothèque standard
raisonnablement optimisée, il n'est pas nécessaire de passer par
référence.

Cependant je suis d'accord avec Fabien: pour la clarté du code,
il faut mieux utiliser l'idiome habituel.

Et puis aussi, autant prendre l'habitude. Comme ça, quand tu
seras dans un cas où il faut passer par rérérence, tu n'auras pas
le mauvais réflexe...

--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"


Avatar
Pierre Maurette
Andre Heinen a écrit:
[...]
Cependant je suis d'accord avec Fabien: pour la clarté du code,
il faut mieux utiliser l'idiome habituel.

Et puis aussi, autant prendre l'habitude. Comme ça, quand tu
seras dans un cas où il faut passer par rérérence, tu n'auras pas
le mauvais réflexe...
Tout à fait convaincu, d'accord avec vous et Fabien.

Merci
--
Pierre

Avatar
Pierre Maurette
Fabien LE LEZ a écrit:

On Tue, 31 Aug 2004 15:34:11 +0200, Pierre Maurette
:
[...]

Et si AjouteNumLignes() est une méthode,


Une fonction membre, tu veux dire ?
Oui.

Il me semblait que je pouvais écrire "méthode [d'instance par
défaut]", et "méthode de classe [static]".

serait-il admissible de
conserver les char*, étant entendu que ce sont des propriétés private?


Franchement, je n'ai rien du tout contre les "char const*". Les
"char*" tout court, par contre, posent beaucoup plus problème.
Je pensais effectivement à des const char*.

--
Pierre


Avatar
Fabien LE LEZ
On Tue, 31 Aug 2004 16:48:57 +0200, Pierre Maurette
:

Une fonction membre, tu veux dire ?
Oui.

Il me semblait que je pouvais écrire "méthode [d'instance par
défaut]", et "méthode de classe [static]".


En programmation objet, et dans certains langages objet, oui.
En C++, l'usage est d'employer l'expression "fonction membre" pour les
fonctions membres, et de réserver le mot "méthode" à des techniques
permettant d'obtenir un code donné (ou n'importe quoi d'autre,
d'ailleurs). Exemples : la méthode habituelle pour passer une
std::string en argument d'une fonction membre est le passage par
référence constante ; la méthode classique pour s'assurer qu'une
classe aura une seule instance dans tout le programme est
d'implémenter le pattern "singleton".

Mais bon, si tu tiens vraiment à employer le mot "méthode" à la place
de "fonction membre", libre à toi -- on te conprendra ;-)
[Après tout, y'a même des gens qui appellent les bibliothèques
"magasins de bouquins" (ou "librairies") ]


--
;-)


1 2 3 4 5