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
Fabien LE LEZ
On Sat, 15 Oct 2005 09:25:49 +0200, Franck Branjonneau
:

Même dans le cas des constructeurs (dont la liste d'initialisation est
non vide) ?


C'est effectivement le seul cas où ça pourrait être utile.

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).

Avatar
Aurélien Barbier-Accary
On Sat, 15 Oct 2005 05:11:41 +0200, Aurélien Barbier-Accary
:


static const Truc val;
static const Truc fonc() { return Truc(-1.0, 0.0); }
// ces valeurs n'ont pas à être modifiées, elles jouent un rôle de constantes



Gnii ?..

Le "static const Truc val;" est correct, il n'y a rien à dire.

Le const de "static const Truc fonc()" est au contraire inutile : même
si tu ne spécifies pas "const", l'objet retourné est de toutes façons
est une rvalue :

class C
{
public:
static int fonc() { return 5; }
};

int main()
{
C::fonc()= 3; // Erreur ici car C::fonc() est une rvalue.
}



Non, ce n'est pas inutile, la preuve est donnée par l'exemple suivant qui est
possible à tort si on ne met pas le const qui fait débat :

class Truc
{
protected:
double d1, d2;
public:
Truc(const double& a=0, const double& b=0) { d1=a; d2=b; }
Truc& operator=(const Truc& t)
{ d1 = t.d1; d2 = t.d2; }
friend ostream& operator<<(ostream& os, const Truc& t)
{ os << t.d1 << ", " << t.d2 << endl; return os; }
};

class C
{
public:
static const Truc fonc() { return Truc(2,3); }
};

int main(int argc, char* argv[])
{
cout << (C::fonc()= Truc(1,0));
return 0;
}

const Truc cB::val = Truc(1.0, 0.0);
Pourquoi une écriture si compliquée ?

const Truc cB::val (1.0, 0.0);
est plus simple, et évite une copie inutile.



alors là c'est une habitude de travail prise à force d'insistance d'un de mes
chefs, mais apparemment à la contruction les deux instructions seraient
équivalentes car détectées par le compilateur !?
Mais tu as raison, il faudrait que je reprenne de bonnes habitudes.

Pour le reste nous y avons tout deux déjà répondu dans un autre fil.


Avatar
Aurélien Barbier-Accary
Aurélien Barbier-Accary écrivait:


Chez moi (gcc), ça m'indique des erreurs dans la fonction qui suit
le prototype de la fonction membre statique.



Ton code me semble correct (modulo s/classe/class/). Puisque l'erreur
apparaît après le prototype et uniquement dans le cpp, je chercherais
si je n'inclus pas dans ce cpp un fichier qui définit une macro fonc.



Bien vu mais en fait c'était encore plus bête (étrange) que ça.
cf le fil intitulé:
[Boulet] pas un pb de fonction statique mais de function try block :-(
Désolé mais je ne sais pas faire de lien vers des messages de news.

Merci pour ta réponse !!


Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 10:38:15 +0200, Aurélien Barbier-Accary
:

Désolé mais je ne sais pas faire de lien vers des messages de news.


C'est fort simple : il suffit de prendre le message-id et d'écrire
"news:" devant.
Par exemple, ton message de 10h38 (auquel je réponds) a le header
suivant :
Message-ID: <4350bff8$0$21232$

Le lien est donc :

<news:4350bff8$0$21232$

Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 10:35:02 +0200, Aurélien Barbier-Accary
:
[...]


Le code suivant est correct :

class C
{
public:
static Truc fonc() { return Truc(2,3); }
};

int main()
{
std::cout << (C::fonc()= Truc(1,0));
}

On peut se poser des questions sur le programmeur qui a écrit ça, mais
bon...
En quoi est-ce gênant que l'affectation soit possible ?

Avatar
Franck Branjonneau
Aurélien Barbier-Accary écrivait:

const Truc cB::val = Truc(1.0, 0.0);
Pourquoi une écriture si compliquée ?

const Truc cB::val (1.0, 0.0);
est plus simple, et évite une copie inutile.



Le compilateur peut faire l'élision de la copie.

mais apparemment à la contruction les deux instructions seraient
équivalentes car détectées par le compilateur !?


Non. Si tu utilises la syntaxe avec affectation le type doit être
constructible par copie.

Mais tu as raison, il faudrait que je reprenne de bonnes habitudes.


Ça se perd ?
--
Franck Branjonneau



Avatar
Franck Branjonneau
Fabien LE LEZ écrivait:

On Sat, 15 Oct 2005 10:35:02 +0200, Aurélien Barbier-Accary
:
[...]


Le code suivant est correct :

class C
{
public:
static Truc fonc() { return Truc(2,3); }
};

int main()
{
std::cout << (C::fonc()= Truc(1,0));
}

On peut se poser des questions sur le programmeur qui a écrit ça, mais
bon...


Original ;-)

En quoi est-ce gênant que l'affectation soit possible ?


Si mes souvenirs sont bons c'est discuté dans un des premiers
GotW. Eviter des choses commme a+b=c;.
--
Franck Branjonneau


Avatar
Franck Branjonneau
Fabien LE LEZ écrivait:

On Sat, 15 Oct 2005 09:25:49 +0200, Franck Branjonneau
:

Même dans le cas des constructeurs (dont la liste d'initialisation est
non vide) ?


C'est effectivement le seul cas où ça pourrait être utile.

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).


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;
p1= p2= p3= &default;

}
--
Franck Branjonneau


Avatar
Aurélien Barbier-Accary
On Sat, 15 Oct 2005 10:38:15 +0200, Aurélien Barbier-Accary
:


Désolé mais je ne sais pas faire de lien vers des messages de news.



C'est fort simple : il suffit de prendre le message-id et d'écrire
"news:" devant.
Par exemple, ton message de 10h38 (auquel je réponds) a le header
suivant :
Message-ID: <4350bff8$0$21232$

Le lien est donc :

<news:4350bff8$0$21232$



ok, merci !


Avatar
Fabien LE LEZ
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.
D'ailleurs, tu viens apporter de l'eau à mon moulin en déclarant à ton
insu un pointeur et trois entiers...

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


Supposons que "p2(initialize())" lance une exception

} catch(...) {

delete p1;


OK

delete p2;


Ça donne quoi, ça ?
Si je ne m'abuse, c'est un comportement indéfini, puisqu'on ne peut
pas prévoir à l'avance la valeur de p2.

delete p3;
p1= p2= p3= &default;



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;
}
}
};

1 2 3 4