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

[Débutant] Retour de fonction "static" et castage

8 réponses
Avatar
tsalm
Bonjour,

Le code ci-dessous ne veut pas compiler, j'ai une erreur :
<< impossible de convertir de 'int *(__cdecl *)(void)' en 'int *' >>


/* ----------- CODE --------------- */
class A
{
private:
static int* _v;

public:

static int* v()
{
return _v;
}

};

void _tmain(int argc, _TCHAR* argv[])
{
int* a = A::v ; // <-- Erreur
// int* a = (int*) A::v ; <-- OK
}
/* ---------- END CODE ------------- */


Par contre, si je cast A::v en (int*). Ca fonctionne.

Pourquoi alors que le type retourné est pourtant bien un "int*" ?

D'avance merci,
TSalm

8 réponses

Avatar
tsalm
> /* ----------- CODE --------------- */
class A
{
private:
static int* _v;

public:

static int* v()
{
return _v;
}

};

void _tmain(int argc, _TCHAR* argv[])
{
int* a = A::v ; // <-- Erreur
// int* a = (int*) A::v ; <-- OK
}
/* ---------- END CODE ------------- */




Oula. Ce code se compile bien, mais le linkage ne passe en fait pas :
error LNK2001: symbole externe non résolu "private: static int * A::_v"
(?@@0PAHA)

Y a t-il une solution ?
Avatar
Mickaël Wolff
tsalm wrote:

Oula. Ce code se compile bien, mais le linkage ne passe en fait pas :
error LNK2001: symbole externe non résolu "private: static int *
A::_v" (?@@0PAHA)



Il faut que tu indiques au compilateur où doit etre stocké ta donnée
membre static.

Dans l'en-tete de la classe :
extern int * A::_v ;

Dans l'unité de compilation qui doit accueillir la donnée membre :
int * A::_v ;

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Avatar
Fabien LE LEZ
On Wed, 05 Aug 2009 22:54:47 +0200, tsalm :

static int* v()
{
return _v;
}



void _tmain(int argc, _TCHAR* argv[])
{
int* a = A::v ; // <-- Erreur



Ah ben oui. v() est une fonction, il faut donc l'appeler :

int* a= A::v();
Avatar
James Kanze
On Aug 5, 10:54 pm, tsalm wrote:

Le code ci-dessous ne veut pas compiler, j'ai une erreur :
<< impossible de convertir de 'int *(__cdecl *)(void)' en 'int *' >>



Le premier, c'est un pointeur à une fonction. Le deuxième, c'est
un pointeur à une donnée. Il n'y a effectivement aucune
conversion entre les deux in C++ ; il y a bien des machines où
ils n'ont pas la même taille ou la même représentation. (C'est
en revanche une extension courante de permettre la conversion
avec reinterpret_cast, si la machine le permet.)

/* ----------- CODE --------------- */
class A
{
private:
static int* _v;



public:

static int* v()
{
return _v;
}
};



void _tmain(int argc, _TCHAR* argv[])



Tu veux dire :
int main( int argc, char** argv )
(ou simplement
int main()
, vue que tu ne t'en sers pas des paramètres d'invocation).

{
int* a = A::v ; // <-- Erreur



C'est encore un autre problème. D'abord, qu'est-ce que doit
signifier A::v ici ? A::v désigne une fonction membre ; il n'y a
que deux choses qu'on peut faire avec une fonction membre :
l'appeler (A::v() : puisque la fonction est statique, tu n'as
pas besoin d'objet), ou en prendre l'adresse (&A::v, ce qui
donnerait un pointeur à une fonction membre -- à ne pas
confondre avec un pointeur à une fonction -- si la fonction
n'était pas statique, mais dans ce cas-ci, donne un pointeur à
une fonction normale).

En admettant que c'est l'adresse que tu veux (puisque certains
compilateurs permet d'omettre l'opérateur &, comme extension,
bien qu'on se démande bien pourquoi), Ce qui te reste, c'est
toujours une adresse à une fonction. Qui n'a rien avoir avec
l'adresse d'un int (adresse de donnée).

// int* a = (int*) A::v ; <-- OK}



Pas OK. Mais beaucoup de compilateurs acceptera :
int* a = (int*) &A::v ;
, même si la norme actuelle exige un « diagnostique ». Si tu as
réelement besoin de ce genre de conversion (et certaines
fonctions dans l'API d'Unix renvoie un pointeur à une fonction
dans un void*), il faut quelque chose du genre :
int* a ;
reinterpret_cast< int* (*&)() >( a ) = &A::v ;

/* ---------- END CODE ------------- */



Par contre, si je cast A::v en (int*). Ca fonctionne.



Pourquoi alors que le type retourné est pourtant bien un
"int*" ?



Parce que l'adresse d'une fonction n'est pas l'adresse d'un int.
Si tu veux l'int* de la valeur de retour, il faut appeler la
fonction :
int* a = A::v() ;

--
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
tsalm
>> Oula. Ce code se compile bien, mais le linkage ne passe en fait pas :
error LNK2001: symbole externe non résolu "private: static int *
A::_v" (?@@0PAHA)



Il faut que tu indiques au compilateur où doit etre stocké ta donnée
membre static.

Dans l'en-tete de la classe :
extern int * A::_v ;

Dans l'unité de compilation qui doit accueillir la donnée membre :
int * A::_v ;



Oula (encore).
Je penses que tout le monde aura compris que je veux juste récupérer le
pointeur sur la variable "int* _v" :-)
Désolé pour cette erreur. Et merci pour vos réponse.

Le code correct est donc :
/* ========== CODE =========== */
class A
{
private:
static int* _v;

public:
static int* v()
{
return _v;
}

};


void _tmain(int argc, _TCHAR* argv[])
{
int* a = A::v() ;
}
/* ======== END CODE ========= */


Qui me retourne cette fois l'erreur de linkage :
error LNK2001: symbole externe non résolu "public: static int * A::_v"
(?@@2PAHA)

D'avance merci.
Avatar
Wykaaa
tsalm a écrit :
Oula. Ce code se compile bien, mais le linkage ne passe en fait pas :
error LNK2001: symbole externe non résolu "private: static int *
A::_v" (?@@0PAHA)



Il faut que tu indiques au compilateur où doit etre stocké ta donnée
membre static.

Dans l'en-tete de la classe :
extern int * A::_v ;

Dans l'unité de compilation qui doit accueillir la donnée membre :
int * A::_v ;



Oula (encore).
Je penses que tout le monde aura compris que je veux juste récupérer le
pointeur sur la variable "int* _v" :-)
Désolé pour cette erreur. Et merci pour vos réponse.

Le code correct est donc :
/* ========== CODE =========== */
class A
{
private:
static int* _v;

public:
static int* v()
{
return _v;
}

};


void _tmain(int argc, _TCHAR* argv[])
{
int* a = A::v() ;
}
/* ======== END CODE ========= */


Qui me retourne cette fois l'erreur de linkage :
error LNK2001: symbole externe non résolu "public: static int *
A::_v" (?@@2PAHA)

D'avance merci.



Ben oui, tu n'as pas de définition de A::_v.

Il te faut définir _v en dehors de tout bloc :
int* A::_v = ... ;

La déclaration d'un attribut static dans une classe nécessite que tu
aies quelque part la définition.
Je cite le "Working Draft, Standard for Programming Language C++" du 4
octobre 2008 :

The declaration of a static data member in its class definition is not a
definition and may be of an incomplete
type other than cv-qualified void. The definition for a static data
member shall appear in a namespace
scope enclosing the member’s class definition. In the definition at
namespace scope, the name of the static
data member shall be qualified by its class name using the :: operator.
The initializer expression in the
definition of a static data member is in the scope of its class (3.3.6).
[ Example:
class process {
static process* run_chain;
static process* running;
};
process* process::running = get_main();
process* process::run_chain = running;
Avatar
tsalm
>> /* ========== CODE =========== */
class A
{
private:
static int* _v;
public:
static int* v()
{
return _v;
}
};
void _tmain(int argc, _TCHAR* argv[])
{
int* a = A::v() ;
}
/* ======== END CODE ========= */
Qui me retourne cette fois l'erreur de linkage :
error LNK2001: symbole externe non résolu "public: static int *
A::_v" (?@@2PAHA)
D'avance merci.



Ben oui, tu n'as pas de définition de A::_v.

Il te faut définir _v en dehors de tout bloc :
int* A::_v = ... ;

La déclaration d'un attribut static dans une classe nécessite que tu
aies quelque part la définition.



Merci. Ca fonctionne parfaitement.
Avatar
tsalm
>
void _tmain(int argc, _TCHAR* argv[])



Tu veux dire :
int main( int argc, char** argv )
(ou simplement
int main()
, vue que tu ne t'en sers pas des paramètres d'invocation).




C'est la fonction "main" proposée par défaut par Visual Studio.
Mais, si je comprends bien, il y a une différence entre _TCHAR* et char**
:
http://msdn.microsoft.com/en-us/library/cc842072.aspx

En tout cas, merci pour tes réponses toujours très riches d'enseignements.