OVH Cloud OVH Cloud

peut-on définir une fonction membre statique dans un fichier .cpp ?

35 réponses
Avatar
Aurélien Barbier-Accary
Bonjour,

petite question comme ça, tout est dans le titre.
Puisqu'on peut écrire

// dans le .hpp
classe cA
{
public:
static const double val;
static const double fonc(const double& d) { return 2*d; }
//...
};
// dans le .cpp
const double cA::val = 1.0;

Comment écrire ceci :

// dans le .hpp
classe cB
{
public:
static const double val;
static const double fonc(const double& d);
//...
};
// dans le .cpp
const double cB::val = 1.0;
const double cB::fonc(const double& d) { return 2*d; }

Chez moi (gcc), ça m'indique des erreurs dans la fonction qui suit le prototype
de la fonction membre statique.
J'ai essayé de ne pas définir une fonction mais un pointeur de fonction mais
j'ai la même erreur.

Quelqu'un a déjà vu/utilisé ce genre de choses ?

Aurélien.

10 réponses

1 2 3 4
Avatar
James Kanze
Fabien LE LEZ wrote:
On Sat, 15 Oct 2005 05:59:23 +0200, Aurélien Barbier-Accary
:


/<type retour> ma_fonction(<params>)
try{ /* code try */ }
catch(std::exception& e) { std::cerr << e.what() << std::endl; }/



Je ne sais pas bien pourquoi cette syntaxe a été introduite,
mais il me semble qu'elle est totalement inutile.


Il a été introduit afin de pouvoir attrapper les exceptions
levées dans la partie initialisateur des constructeurs :

MaClasse::MaClasse()
try {
: elemA( fonctionStatique() )
{
}
catch ( ... ) {
// ...
}

Comment veux-tu trapper une exception levée dans le constructeur
d'elemA ou dans fonctionStatique() sinon ?

S'il s'applique aux autres fonctions, je crois que c'est sûrtout
par souci de homogénéité, pour éviter que les constructeurs
soient un cas spécial.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


Avatar
James Kanze
Fabien LE LEZ wrote:

Une réécriture minimale de cette classe serait :


struct S
{
static int const default= 0;
int *p1, *p2, *p3;

S() : p1(NULL), p2(NULL), p3(NULL)
{
try
{
p1= initialize();
p2= initialize();
p3= initialize();
}
catch(...)
{
delete p1; delete p2; delete p3;
p1= p2= p3= &default;
}
}
};


Sauf que je crois qu'on préfèrerais une version avec des
pointeurs intelligents.

L'exemple marche bien s'il y a un pointeur et deux int, avec des
fonctions initialize1, initialize2 et initialize3, où
initialize2 ou initialize3 pourrait lever une exception. J'ai dû
mal à imaginer un exemple réaliste, et j'avoue ne jamais en avoir
senti le besoin. Mais de là à dire que ça n'a aucune utilité ?

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Avatar
Fabien LE LEZ
On Sun, 16 Oct 2005 00:07:45 +0200, James Kanze :

Sauf que je crois qu'on préfèrerais une version avec des
pointeurs intelligents.


Certes. C'est pour ça que j'ai écrit "réécriture minimale". J'entends
par là "Remplacer un programme qui ne fonctionne pas, en un programme
qui fonctionne, tout en changeant le moins de choses possibles."

Avatar
David Deharbe
Cela permet au compilateur de détecter l'erreur classique où le
programmeur utilise operator= au lieu d'operator==.

David.
--
Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 14:45:19 +0200, Franck Branjonneau
:

struct S {

static int const default= 0;
int * p1, p2, p3, p4;

S() try: p1(initialize()), p2(initialize()), p3(initialize()) {

} catch(...) {

delete p1; delete p2; delete p3;


Je viens de me rendre compte que ce code est encore plus incorrect que
ce que j'imaginais : quand on est dans le bloc "catch", si je ne
m'abuse, l'objet de classe S n'a jamais existé. Donc, parler du membre
p1 (ou p2 ou p3) n'a aucun sens.

Avatar
Fabien LE LEZ
On Sun, 16 Oct 2005 00:00:55 +0200, James Kanze :

Il a été introduit afin de pouvoir attrapper les exceptions
levées dans la partie initialisateur des constructeurs :


T'arrive-t-il d'utiliser ce mécanisme ?
Si oui, pourrais-tu me donner un exemple réel ?

Et, accessoirement, que penses-tu de <http://www.gotw.ca/gotw/066.htm>
(ou les items 17 et 18 de "More exceptional C++") ?

Avatar
Franck Branjonneau
Fabien LE LEZ écrivait:

On Sat, 15 Oct 2005 14:45:19 +0200, Franck Branjonneau
:

int * p1, p2, p3, p4;


Je déconseille fortement la déclaration de plusieurs variables sur la
même ligne.


Oui.

Si je ne m'abuse, c'est un comportement indéfini


Oui.

Mon code, complètement erroné, voulait illustrer que si

Note toutefois que si le constructeur d'un membre (ou d'une classe de
base) renvoie une exception, l'objet ne peut pas être créé, donc doit
lui-même renvoyer une exception. Les possibilités pour le "catch"
seront alors assez limitées : enregistrement éventuel de l'erreur dans
un fichier log, puis renvoi de l'exception (ou d'une autre exception).


est le comportement le plus général ; il est des cas où ce n'est pas
vrai.
--
Franck Branjonneau


Avatar
Franck Branjonneau
Fabien LE LEZ écrivait:

J'entends par là "Remplacer un programme qui ne fonctionne pas, en
un programme qui fonctionne, tout en changeant le moins de choses
possibles."


Même pas ;-) Il manque s/default/default_/
--
Franck Branjonneau

Avatar
Franck Branjonneau
James Kanze écrivait:

Il a été introduit afin de pouvoir attrapper les exceptions
levées dans la partie initialisateur des constructeurs :

MaClasse::MaClasse()
try {
: elemA( fonctionStatique() )
{
}
catch ( ... ) {
// ...
}


Tu ne l'utilises pas souvent ;-)

MaClasse::MaClasse() try:
elemA( fonctionStatique() )
{
}
catch ( ... ) {
// ...
}
--
Franck Branjonneau

Avatar
Franck Branjonneau
Fabien LE LEZ écrivait:

On Sat, 15 Oct 2005 14:45:19 +0200, Franck Branjonneau
:

struct S {

static int const default= 0;
int * p1, p2, p3, p4;

S() try: p1(initialize()), p2(initialize()), p3(initialize()) {

} catch(...) {

delete p1; delete p2; delete p3;


Je viens de me rendre compte que ce code est encore plus incorrect que
ce que j'imaginais : quand on est dans le bloc "catch", si je ne
m'abuse, l'objet de classe S n'a jamais existé.


En fait, la norme dit que toute partie correctement construite est
détruite à l'entrée du handler.

Donc, parler du membre p1 (ou p2 ou p3) n'a aucun sens.


Oui c'est du comportement indéfini. On ne peut utiliser que les
membres statiques de la classe et les paramètres du constructeur.

De plus, dans le cas d'un constructeur ou d'un destructeur,
l'exception attrapée est relancée si le flot de contrôle atteint la
fin du handler.
--
Franck Branjonneau


1 2 3 4