Bonjour tout le monde,

Je fais un premier exercice qui se passait bien jusqu'à il y'a 2 minutes.

J'obtiens un message d'erreur lors du linking :

Linking...
Vehicule3.obj : error LNK2001: unresolved external symbol "private: static bool __cdecl CLeTout::FctnTraiterLigne(class CChargeurFichierTexte const &,void *)" (?FctnTraiterLigne@CLeTout@@CA_NABVCChargeurFichierTexte@@PAX@Z)
Debug/vehicule3.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
La ligne qui pose problème est celle-ci :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
return Chargeur.Charger(NomFichier,'\t',CLeTout::FctnTraiterLigne,this);
car quand je fais "return true", tout se passe bien et je n'obtiens aucun message d'erreur lors de la compilation et du linking.

voici mon code : Merci d'avance pour votre aide.

beegees

Voici le fichier qui pose problème (où s'est peut être le chaine.h ou le chaine.cpp) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <BasicConsole.h>
#include "vehicule3.h"
#include "chaine.h"
 
 
Vehicule3::Vehicule3()
:NombreDePlace(0)
{
}
 
Vehicule3::~Vehicule3()
{
}
 
CVoiture::CVoiture()
:m_VTM(0.0)
{
}
 
CVoiture::~CVoiture()
{
}
 
CTabVoitures::CTabVoitures()
:m_Nombre(0),m_Tableau(NULL)
{
}
 
CTabVoitures::~CTabVoitures()
{
}
 
CLeTout::CLeTout()
{
 
}
 
CLeTout::~CLeTout()
{
 
}
 
bool	CLeTout::Charger(const char* NomFichier)
{
 
	CChargeurFichierTexte	Chargeur;
 
 
	return Chargeur.Charger(NomFichier,'\t',CLeTout::FctnTraiterLigne,this);
}

voici le chaine.h :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#ifndef CHAINE_H
#define CHAINE_H
 
class CChaine
{
public:
	CChaine();																// Constructeur par défaut
	CChaine(const CChaine& Source);											// Constructeur par copie
	CChaine(const char* UneChaine);											// Constructeur spécifique
	~CChaine();																// Destructeur
 
	const char*		Chaine() const;											// Accesseur du texte de la chaîne
	bool			EstNull() const;										// Accesseur de test sur le texte (m_Chaine == NULL)
	bool			EstVide() const;										// Accesseur de test sur le texte (m_Chaine == NULL) || (m_Chaine == "")
 
	void			Vider();												// Modificateur permettant de supprimer le texte de la chaîne (on revient à NULL)
	bool			Chaine(const char* UneChaine);							// Modificateur du texte de la chaîne
 
private:
	char*			m_Chaine;												// Membre contenant l'adresse du tableau de caractères alloué dynamiquement
};
 
class CChaineComposee : private CChaine
{
public:
	CChaineComposee();														// Constructeur par défaut
	CChaineComposee(const CChaineComposee& Source);							// Constructeur par copie
	CChaineComposee(const char* UneChaine, char UnSeparateur);				// Constructeur spécifique
	~CChaineComposee();														// Destructeur
 
	long			NombreChamps() const;									// Accesseur du nombre de champs
	const char*		Champs(long Indice) const;								// Accesseur d'un champ
 
	bool			Definir(const char* UneChaine, char UnSeparateur);		// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
 
private:
	bool			Decomposer(char UnSeparateur);							// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
 
private:
	long			m_NbrChamps;
	char**			m_Champs;
};
 
////////////////////////////////
// Class CChargeurFichierTexte//
////////////////////////////////
 
class CChargeurFichierTexte : public CChaineComposee
 
/*Donc en fait cette classe CChargeurFichierTexte à un moment donné ce qu'elle va contenir 
comme information se sont les données d'une ligne mais déjà décomposée, sont but s'est 
d'arriver à lire une ligne du fichier texte et de la décomposer automatiquement et donc en 
servant des fonctionnalités publiques de la classe et bien on aura la possibilité de savoir 
ce qu'il y'avait comme information sur la ligne (le nombre de champs et les valeurs  sous 
forme de chaîne de caractère des différents champs) et ce qu'elle fournira en plus s'est 
une méthode de chargement où on peut passer le nom du fichier et la fonction à appeler pour 
pouvoir traiter les données d'une ligne puisque le but de la fonction charger s'est de :
 
-	lire une ligne 
-	d'appeler la fonction passer par celui qui utilise cette classe là
-	et ensuite d'exécuter cette fonction
-	et ensuite de passer à la lecture de la ligne suivante et ce jusqu'à la fin du fichier.
*/
{
public:
	CChargeurFichierTexte();
	~CChargeurFichierTexte();
 
	bool			Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte);
 
private:
};
 
#endif//CHAINE_H
et voici le chaine.cpp :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <BasicConsole.h>
#include "chaine.h"
#include "chaine.h"
 
 
////////////////////
// Classe CChaine //
////////////////////
 
CChaine::CChaine() //constructeur par défaut
:m_Chaine(NULL)
{
}
 
CChaine::CChaine(const CChaine& Source) //constructeur par copie
:m_Chaine(NULL)
{
	Chaine(Source.m_Chaine);
}
 
CChaine::CChaine(const char* UneChaine) //constructeur spécifique
:m_Chaine(NULL)
{
	Chaine(UneChaine);
}
 
CChaine::~CChaine() //destructeur
{
	Vider();
}
 
void CChaine::Vider()
{
	if (m_Chaine != NULL)
	{
		free(m_Chaine);
		m_Chaine = NULL;
	}
}
 
bool CChaine::Chaine(const char* UneChaine)
{
	if (UneChaine == NULL) return false;
	void* Nouveau = realloc(m_Chaine,(strlen(UneChaine)+1)*sizeof(char));
	if (Nouveau == NULL) return false;
	m_Chaine = (char*)Nouveau;
	strcpy(m_Chaine,UneChaine);
	return true;
}
 
const char* CChaine::Chaine() const
{
	return (m_Chaine != NULL) ? m_Chaine : "";
}
 
bool CChaine::EstNull() const
{
	return (m_Chaine == NULL);
}
 
bool CChaine::EstVide() const
{
	return (m_Chaine == NULL) || (m_Chaine[0] == 0);
}
 
 
////////////////////////////
// Classe CChaineComposee //
////////////////////////////
 
CChaineComposee::CChaineComposee()
:m_NbrChamps(0),m_Champs(NULL)
{
}
 
CChaineComposee::CChaineComposee(const CChaineComposee& Source)
:CChaine(Source),m_NbrChamps(0),m_Champs(NULL)
{
	if (Source.m_NbrChamps > 0)
	{
		m_Champs = (char**)malloc(Source.m_NbrChamps*sizeof(char*));
		if (m_Champs != NULL)
		{
			m_NbrChamps = Source.m_NbrChamps;
			for (long n=0; n < Source.m_NbrChamps; n++)
			{
				long PosRel = Source.m_Champs[n] - Source.m_Champs[0];
				m_Champs[n] = ((char*)Chaine()) + PosRel;
			}
		}
	}
}
 
CChaineComposee::CChaineComposee(const char* UneChaine, char UnSeparateur)
:CChaine(UneChaine),m_NbrChamps(0),m_Champs(NULL)
{
	Decomposer(UnSeparateur);
}
 
CChaineComposee::~CChaineComposee()
{
	if (m_Champs) free(m_Champs);
}
 
long CChaineComposee::NombreChamps() const
{
	return m_NbrChamps;
}
 
const char* CChaineComposee::Champs(long Indice) const
{
	return ( (Indice >= 0) && (Indice < m_NbrChamps) ) ? m_Champs[Indice] : "";
}
 
bool CChaineComposee::Definir(const char* UneChaine, char UnSeparateur)
{
	if (!Chaine(UneChaine)) return false;
	return Decomposer(UnSeparateur);
}
 
bool CChaineComposee::Decomposer(char UnSeparateur)
{
	m_NbrChamps = 0;
	char* Texte = (char*)Chaine();
	if (Texte == NULL) return false;
	void* Nouveau = realloc(m_Champs,1*sizeof(char*));
	if (Nouveau == NULL)
	{
		if (m_Champs)
		{
			free(m_Champs);
			m_Champs = NULL;
		}
		return false;
	}
	m_Champs = (char**)Nouveau;
	m_Champs[m_NbrChamps] = Texte;
	m_NbrChamps++;
	while (true)
	{
		char* Delimiteur = strchr(Texte,UnSeparateur);
		if (Delimiteur == NULL) return true;
		*Delimiteur = 0;
		Texte = Delimiteur + 1;
		void* Nouveau = realloc(m_Champs,(m_NbrChamps+1)*sizeof(char*));
		if (Nouveau == NULL) return false;
		m_Champs = (char**)Nouveau;
		m_Champs[m_NbrChamps] = Texte;
		m_NbrChamps++;
	}
}
 
 
//////////////////////////////////
// Classe CChargeurFichierTexte //
//////////////////////////////////
 
CChargeurFichierTexte::CChargeurFichierTexte()
{
}
 
CChargeurFichierTexte::~CChargeurFichierTexte()
{
}
 
bool CChargeurFichierTexte::Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte)
{
	const long		TailleLigne = 500;
	char			Ligne[TailleLigne+1];
	FILE*			Fichier;
 
	if ( (NomFichier == NULL) || (*NomFichier == 0) ) return false;
	Fichier = fopen(NomFichier,"rt");
	while (fgets(Ligne,TailleLigne,Fichier) != NULL)
	{
		long i = strlen(Ligne);
		if ( (i > 0) && (Ligne[i-1] == '\n') ) Ligne[i-1] = 0;
		if (Definir(Ligne,'\t'))
		{
			if (!FctnTraiterLigne(*this,Contexte))
			{
				fclose(Fichier);
				return false;
			}
		}
	}
	fclose(Fichier);
	return true;
}
et pour être complet, voici le main :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <BasicConsole.h>
#include "vehicule3.h"
#include "chaine.h"
 
void main()
{
 
	CLeTout LeTout;
 
	if(LeTout.Charger("Vehicules.txt")) printf("ok");
 
 
 
 
}
et le header :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <BasicConsole.h>
#include "chaine.h"
 
 
class Vehicule3
{
public:
 
	Vehicule3();
	~Vehicule3();
 
 
 
	short		NombreDePlace;
 
private:
	CChaine		m_Nom;
	CChaine		m_Immatriculation;
 
};
 
class CVoiture : public Vehicule3
{
public:
	CVoiture();
	~CVoiture();
 
private:
	double		m_VTM; //Volume transportable de marchandise
 
 
};
 
class CTabVoitures
{
public:
	CTabVoitures();
	~CTabVoitures();
private:
	long		m_Nombre;
	CVoiture**	m_Tableau;
 
};
 
class CLeTout
{
public:
	CLeTout();
	~CLeTout();
 
	bool		Charger(const char* NomFichier);
 
private:
 
	private:
	static bool			FctnTraiterLigne(const CChargeurFichierTexte& CC, void* Contexte);
	bool				TraiterLigne(const CChargeurFichierTexte& CC);
 
 
private:
	CTabVoitures	m_TV; //Tableau de voitures
};