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

Dépendances croisées entre classes...

9 réponses
Avatar
Jean-Noël Mégoz
Salut !

Voici une question qui est sans doute un grand classique de ce NG !

J'ai défini les classes Contrainst, Task, et TheTasks :
- L'instance de TheTasks contient un tableau de pointeurs vers les instances
de Task
- Les instances de Taskcontiennent chacune un tableau de pointeurs vers des
instances de Contrainst
- Les instances de Contrainst ont une fonction membre qui a besoin de faire
référence à l'instance de TheTasks.

Vous voyez le problème...
J'ai voulu appliquer la solution qui me semblait la bonne, à savoir :
- faire précéder la déclaration de la classe Contrainst dans "constraint.h"
par "class TheTasks;"
- mettre #include "constraint.h" dans "task.h"
- mettre #include "task.h" dans "theTasks.h"

Eh bien, ça ne doit pas être suffisant, ou je me suis trompé quelque part,
car ça ne compile pas !
Qq'un pourrait-t-il me préciser la chose, svp ?

J.No.

9 réponses

Avatar
Loïc Joly
Jean-Noël Mégoz wrote:

Salut !

Voici une question qui est sans doute un grand classique de ce NG !

J'ai défini les classes Contrainst, Task, et TheTasks :
- L'instance de TheTasks contient un tableau de pointeurs vers les instances
de Task
- Les instances de Taskcontiennent chacune un tableau de pointeurs vers des
instances de Contrainst
- Les instances de Contrainst ont une fonction membre qui a besoin de faire
référence à l'instance de TheTasks.

Vous voyez le problème...
J'ai voulu appliquer la solution qui me semblait la bonne, à savoir :
- faire précéder la déclaration de la classe Contrainst dans "constraint.h"
par "class TheTasks;"
- mettre #include "constraint.h" dans "task.h"
- mettre #include "task.h" dans "theTasks.h"


Tu peux faire encore mieux d'après ce que tu décris :
- Dans "task.h", mettre simplement class Constraint;
- Dans "theTasks.h", mettre simplement class Task;

Puisque dans les deux cas, tu passe par des pointeurs, et n'a donc pas
beosin de la définition de ces classes, juste leur déclaration.


Eh bien, ça ne doit pas être suffisant, ou je me suis trompé quelque part,
car ça ne compile pas !


A priori, je ne vois pas de problèmes. Et comme ma boule de cristal est
chez le garagiste, pourrais-tu préciser un peu (Le concept d'exemple
complet et minimum peut faire avancer les choses) ?

Qq'un pourrait-t-il me préciser la chose, svp ?


Au hasard, je dirais que, comme dans ce post, tu as mélangé des
Contrainst et des Constraint.

--
Loïc

Avatar
Jean-Noël Mégoz
"Loïc Joly" a écrit dans le message de
news:c8qghf$3rm$
Jean-Noël Mégoz wrote:

A priori, je ne vois pas de problèmes. Et comme ma boule de cristal est
chez le garagiste, pourrais-tu préciser un peu (Le concept d'exemple
complet et minimum peut faire avancer les choses) ?



Bon, je vais tenter de donner plus d'infos sans vous étaler tout mon code !
;)
Mes .h sont les suivants (je vous fais grâce des directives de compil et des
#define) :

-- constraint.h ----------------------------------------------
class TheTasks;
class Constraint
{
private:
int toTask;
int type;
int time;
public:
Constraint(int task, int typ, int tim);
~Constraint();
int ComputeStartDate(int fromTask, const TheTasks& tasks) const;
};
-- task.h ----------------------------------------------------
#include "constraint.h"
class Task
{
private:
int nbConstraints;
Constraint** constraintArray;
[...]
public:
Task(char name, int time);
~Task();
[...]
Constraint* GetConstraint(int nth) const;
};

-- theTask.h -------------------------------------------------
#include "task.h"
class TheTasks
{
private:
int nbTasks;
Task** taskArray;
[...]
public:
Tasks();
~Tasks();
[...]
};

-- constraint.cpp --------------------------------------------
#include "constraint.h"
int Constraint::ComputeStartDate(int fromTask, const TheTasks& tasks) const
{
int date;
switch(type)
{
case START_TO_START :
date = time + tasks.task[fromTask]->GetStartDate();
break;
[...]
}
return date;
}

--------------------------------------------------------------

Le compilo hurle non pas dans la déclaration de la classe Constraint, ni
même dans celle de la fonction ComputeStartDate, mais lors de l'appel à
l'objet "tasks" passé en paramètre. Et c'est bien normal car si lui dire que
"TheTasks" est une classe lui suffit dans un premier temps, il a besoin d'en
savoir plus dans la fonction !
Je ne vois donc pas comment faire. Peut-être est-ce un problème de
modélisation : la fonction ComputeStartDate devrait-elle membre de TheTasks
plutôt que Constraint ? Ce serait étonnant dans la mesure où son résultat
dépend bel et bien de la contrainte qui l'appelle...

Tu peux faire encore mieux d'après ce que tu décris :
- Dans "task.h", mettre simplement class Constraint;
- Dans "theTasks.h", mettre simplement class Task;

Puisque dans les deux cas, tu passe par des pointeurs, et n'a donc pas
beosin de la définition de ces classes, juste leur déclaration.


J'aurais alors les même problèmes : les classes se définissent bien, mais
les fonctions membres ne peuvent être compilées !

Au hasard, je dirais que, comme dans ce post, tu as mélangé des
Contrainst et des Constraint.


Le mailer ne détecte pas les fautes de frappe, mais le compilo, si... Ce
n'est donc pas ça ! ;)

Avatar
Jean-Noël Mégoz
"Jean-Noël Mégoz" a écrit dans le message de
news:40b0ccf6$0$25188$

"Loïc Joly" a écrit dans le message de
news:c8qghf$3rm$
Jean-Noël Mégoz wrote:

-- constraint.cpp --------------------------------------------

#include "constraint.h"
int Constraint::ComputeStartDate(int fromTask, const TheTasks& tasks)
const

{
int date;
switch(type)
{
case START_TO_START :
date = time + tasks.task[fromTask]->GetStartDate();
break;


Dans le case, il faut lire : tasks.taskArray[fromTask]->GetStartDate();
Mais le pb ne vient pas de là de ttes façons.


Avatar
Franck Branjonneau
"Jean-Noël Mégoz" écrivait:

-- constraint.cpp --------------------------------------------
#include "constraint.h"


#include "task.h"

int Constraint::ComputeStartDate(int fromTask, const TheTasks& tasks) const
{
int date;
switch(type)
{
case START_TO_START :
date = time + tasks.task[fromTask]->GetStartDate();


Le compilateur, qui comme Loïc n'a pas de boule de cristal, n'est pas
devin.

break;
[...]
}
return date;
}
--

Franck Branjonneau

Avatar
Jean-Noël Mégoz
"Franck Branjonneau" a écrit dans le message de
news:
Le compilateur, qui comme Loïc n'a pas de boule de cristal, n'est pas
devin.

Merci, ça m'aide beaucoup...

Je demandais justement COMMENT m'en sortir !

Avatar
Jean-Noël Mégoz
"Jean-Noël Mégoz" a écrit dans le message de
news:40b101e2$0$25189$

"Franck Branjonneau" a écrit dans le message de
news:
Merci, ça m'aide beaucoup...
Je demandais justement COMMENT m'en sortir !

Oups, je m'emporte, je m'emporte, et je ne lis pas tout...

Ajouter l'include de "task.h", oui.
Sauf que le compilo bloque avant ça, sur la classe TheTasks, qui bien que
déclarée reste indéfinie...

Je crois que je vais m'y prendre autrement, ce sera plus simple ! :/

Avatar
Loïc Joly
Jean-Noël Mégoz wrote:

"Loïc Joly" a écrit dans le message de
news:c8qghf$3rm$

Jean-Noël Mégoz wrote:

A priori, je ne vois pas de problèmes. Et comme ma boule de cristal est
chez le garagiste, pourrais-tu préciser un peu (Le concept d'exemple
complet et minimum peut faire avancer les choses) ?




Bon, je vais tenter de donner plus d'infos sans vous étaler tout mon code !
;)
Mes .h sont les suivants (je vous fais grâce des directives de compil et des
#define) :


[...]

-- constraint.cpp --------------------------------------------
#include "constraint.h"
int Constraint::ComputeStartDate(int fromTask, const TheTasks& tasks) const
{
int date;
switch(type)
{
case START_TO_START :
date = time + tasks.task[fromTask]->GetStartDate();
break;
[...]
}
return date;
}

--------------------------------------------------------------

Le compilo hurle non pas dans la déclaration de la classe Constraint, ni
même dans celle de la fonction ComputeStartDate, mais lors de l'appel à
l'objet "tasks" passé en paramètre. Et c'est bien normal car si lui dire que
"TheTasks" est une classe lui suffit dans un premier temps, il a besoin d'en
savoir plus dans la fonction !


Oui, il faut dans les .cpp mettre tous les #include correspondant aux
class XXX; que tu as mis dans le .h correspondant.

En effet, même si dans la définition de classe la déclaration anticipée
d'autres classes suffit, elle est souvent insuffisante pour définir les
fonctions de cette classe.

--
Loïc


Avatar
Jean-Noël Mégoz
"Loïc Joly" a écrit dans le message de
news:c8ram6$eun$
Jean-Noël Mégoz wrote:


Oui, il faut dans les .cpp mettre tous les #include correspondant aux
class XXX; que tu as mis dans le .h correspondant.

En effet, même si dans la définition de classe la déclaration anticipée
d'autres classes suffit, elle est souvent insuffisante pour définir les
fonctions de cette classe.



Donc si je te suis bien, je ne mets que la déclaration des classes
nécessaires dans les .h (genre "class Task;"), et dans les .cpp, j'ajoute
les .h correspondants (#include "task.h").

C'est en tous cas ce que je viens de faire, et la compilation se passe bien,
en effet.
Par contre, j'ai toujours un soucis, avec le link, cette fois :
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol

Debug/Tasks.exe : fatal error LNK1120: 1 unresolved externals

Connaissez-vous un moyen de savoir où ça pêche ? VC++ n'est pas très
explicite à ce niveau.

Avatar
Loïc Joly
Jean-Noël Mégoz wrote:

Par contre, j'ai toujours un soucis, avec le link, cette fois :
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol

Debug/Tasks.exe : fatal error LNK1120: 1 unresolved externals

Connaissez-vous un moyen de savoir où ça pêche ? VC++ n'est pas très
explicite à ce niveau.


C'est une erreur spécifique à ton environneemnt de développement (et
donc pour plus d'info, je t'invite à choisir un groupe plus adapté).

En gros, tu as choisi un projet "windows" qui demande une fonction
WinMain, au lieu d'un projet "console" qui se satisfait du main du C++.

--
Loïc