|
|
|
|
Bonjour,
je dois faire un programme mais j'ai 9 erreurs que je ne sais pas comment resoudre, sa commence dont tres mal, j'aurais donc besoin de savoir c'est quoi l'erreur
#include <vector>
#include <iostream.h>
#include <stack>
using namespace std;
template <class T>
class Postfixe
{
Private:
stack<T> Pile;
vector<T> tableau;
Public:
// lit l'expression à évaluer, à partir du clavier, dans tableau et valide si l'expression ne contient que
// les caractères ci-dessus, à savoir les nombres entiers composés de caractères nombres, et les opérateurs ci-dessus.
bool postfix(vector<T> tableau );
// (bonus) teste si l'expression lue contient un nombre valide de parenthèses
bool valider_expression(vector<T> tableau);
// transforme les nombres lus en caractères en valeurs numériques
void transformerennombres(vector<T> tableau);
// transforme l'expression lue en une expression postfixe.
void transformerenpostfixe(stack<T> Pile, vector<T> tableau);
// affiche la valeur de l'expression lue.l
int evaluer_expression(stack<T> Pile, vector<T> tableau);
};
template <class T>
bool Postfixe<T>::postfix(vector<T> tableau)
{
}
template <class T>
bool Postfixe<T>::valider_expression(vector<T> tableau)
{
}
template <class T>
void Postfixe<T>::transformerennombres(vector<T> tableau)
{
}
template <class T>
void Postfixe<T>::transformerenpostfixe(stack<T> Pile, vector<T> tableau)
{
}
template <class T>
int Postfixe<T>::evaluer_expression(stack<T> Pile, vector<T> tableau)
{
}
Merci
Configuration: Windows Vista visual c++ 6.0
1) Pour commencer les fonction template doivent être implémentées dans le header. Or il ne faut pas pas faire de "using namespace std" dans le "global scope" d'un header, car sinon tout fichier qui inclue ce header sera victime du "using namespace std". C'est gênant le jour ou tu es dans un namespace avec des noms en conflits avec des classes de la librairies standard. Pour résumer : il ne fait jamais utiliser de "using namespace std;" au début d'un header.
template <class T>
bool Postfixe<T>::valider_expression(vector<T> & tableau)
{
return true;
}
Syntaxiquement parlant ça ne change rien à ton code, tout se passe comme si tu avais passé l'objet lui-même, mais en réalité tu manipules directement son adresse (et donc tu gagnes en efficacité !). De plus comme le paramètre n'est pas modifié il est mieux de préciser que la fonction ne le modifie pas en rajoutant un const. De même si la méthode ne modifie pas l'instance de classe à laquelle se raccorche (*this), tu es sensé le préciser en rajoutant un const en fin de prototype. template <typename T>
bool Postfixe<T>::valider_expression(const vector<T> & tableau) const
{
std::cout << "mon vecteur est de taille " << tableau.size() << std::endl;
return true;
}
Ici j'ai changé "class T" par "typename T". Les deux syntaxes marchent mais je trouve la seconde meilleure, car ton type template peut être un type de base, une structure et pas forcément une classe. A présent allons un peu plus loin. Une classe template ne se compile pas à proprement parler. En fait tu compiles la classe template pour chaque type d'utilisation. Par exemple si tu utilises des std::vector<int>, des std::vector<double> etc tu compiles autant de classes vector. Ainsi un type template n'a pas vraiment de sens durant la phase de précompilation, en particulier si tu dois accéder à des champs d'une classe template. Par exemple supposons que je veuille utiliser le typedef "const_iterator" d'un std::vector<T>. A ce stade le type std::vector<T> n'est pas encore défini, donc pour feinter le compilateur on utilise le mot clé typename : template <typename T>
bool Postfixe<T>::valider_expression(const vector<T> & tableau) const
{
std::cout << "mon vecteur est de taille " << tableau.size() << std::endl;
// Le type en italique dépend d'au moins un paramètre template (ici T)
// donc doit être précédé d'un typename si on veut accéder
// à un de ses champs (ici le type "const_iterator").
typename std::vector<T>::const_iterator
vit (tableau.begin()),
vend(tableau.end());
for(;vit!=vend;++vit) std::cout << *vit << ' ';
std::cout << std::endl;
return true;
}
Pour le typename retiens juste que quand tu as besoi de l'opérateur :: et que le type devant :: dépend d'un paramètre template, il faut un typename. Tu peux tout à fait faire un tyepdef si tu le souhaites : typedef typename std::vector<T>::const_iterator my_const_iterator; my_const_iterator vit(v.begin()),vend(v.end()); 2) Ensuite attention les mots clés private, protected, public s'écrivent en minuscule. De manière générale en C++ tout s'écrit en minuscule. Mais il arrive que les notations "java" (mettre une majuscule pour les noms de classe, écrire les noms de fonction comme ceci : ceciEstUneFonction) sont utilisées. Personnellement je n'aime pas trop mais après chacun rédige son code à son idée, moi j'en mets juste pour les paramètres templates (par exemple T dans ton exemple) 3) Si tu déclares une fonction dans un header sans l'implémenter (par exemple bool postfix(vector<T> tableau ); est déclarée mais pas implémentée), il faut l'implémenter au dans le fichier source (plop.cpp) correspondant à ton header (plop.hpp) 4) Enfin il ne faut pas inclure <iostream.h> mais <iostream> Bonne chance |
Merci pour tes corrections il m'aide beacoup a comprendre la matiere cependant, que il ya un erreur en debut de programme que je n'arrive pas a trouver :
|
J'ai ajoute des std:: les erreurs disparait mais je veux savoir si c'est correcte
|
C'est syntaxiquement bon modulo trois problèmes
#include <iostream>
void incrementer(int x){
++x;
std::cout << "incrementer : " << x << std::endl;
}
void incrementer1(int & x){
++x;
std::cout << "incrementer1 : " << x << std::endl;
}
void incrementer2(int *x){
++(*x);
std::cout << "incrementer2 : " << x << std::endl;
}
int main(){
int x = 0;
incrementer(x);
std::cout << "main : " << x << std::endl;
incrementer1(x);
std::cout << "main : " << x << std::endl;
incrementer2(&x);
std::cout << "main : " << x << std::endl;
return 0;
}
.. donne à l'exécution : incrementer : 1 main : 0 incrementer1 : 1 main : 1 incrementer2 : 2 main : 2 Au travers de cet exemple tu vois bien que x n'est modifié par incrementer() qu'au sein de son corps de fonction, car incrementer() ne manipule qu'une recopie de la variable x du main(). C'est l'écueil que tu rencontreras par exemple dans ta fonction transformerennombres() - Dans incrementer1() on spécifie au travers de la référence qu'il ne faut pas recopier la variable. C'est la technique qu'on utilise le plus souvent en C++ - Dans incrementer2() on passe directement l'adresse de la variable de la variable x. Pour être plus précis, on devrait dire qu'on recopie l'adresse de la variable x, mais que la valeur de cette adresse est bien toujours l'adresse de la variable x du main. Comme les références n'existent qu'en C++ c'est la seule façon de s'en sortir en C. Quoiqu'il en soit retiens qu'on ne passe que des adresses ou des pointeurs car on manipule bien ce qu'on croit, et surtout on évite de recopier des gros volumes de données. Typiquement dans ta méthode evaluer_expression() il est inutile de recopier Pile et tableau surtout si ces deux structures sont susceptibles d'être grosses et donc longue à recopier. D'une manière générale en C++ on ne passe que des références ou des pointeurs car on veut être potentiellement capable de modifier les paramètres (comme dans incrementer1()), et on veut éviter de recopier des gros paramètres pour rien (comme dans evaluer_expression()). Etant donné que tu ne fais plus de recopie d'objet mais que tu les manipules directement, il est dès lors important de préciser les paramètres que ta fonction est susceptible de modifier (paramètres modifiable ou "donnée résultat"), et ceux qui ne seront jamais modifiés (paramètres constant, identifiés par le mot clé const). En particulier, *this est un paramètre de ta classe à part entière, et il est important de dire s'il est constant ou pas. 2) Ensuite il faut bien voir que tu travailles dans une classe template, donc chaque membre de fonction doit être implémentés dans le fichier dans lequel tu as écrit ta classe. Tu peux soit le faire hors de la classe comme tu avais commencé à le faire dans ton premier post, soit directement dans la classe elle même. 3) Attention ton constructeur doit porter le nom de ta classe. Donc soit tu appelles ta classe "postfixe", soit tu appelles ton constructeur "Postfixe". Enfin un constructeur n'a pas de valeur de retour. Par ailleurs je n'ai pas très bien compris pourquoi tu passes systématiquement "Pile" et "tableau", qui sont deux attributs de ton instance, donc directement accessible. Dans le doute je les ai viré, car si j'ai bien compris ce que tu veux faire, ces méthodes vont tester les attributs d'une instance postfixe p, les modifier, et les afficher. Or dans une méthode C++, la méthode peut accéder aux attributs de l'instance à laquelle elle se rattrache (ici l'instance p)
#include <iostream>
// Début de postfixe.hpp
#include <vector>
#include <stack>
template <typename T>
class postfixe
{
public:
typedef std::stack<T> pile_t;
typedef std::vector<T> tableau_t;
protected:
pile_t pile;
tableau_t tableau;
public:
postfixe(const tableau_t & tableau0):
tableau(tableau0) // recopie tableau0 dans l'attribut tableau
{}
bool valider_expression() const { // const car a priori on ne modifie ni pile, ni tableau
std::cerr << "valider_expression: not yet implemented" << std::endl;
return false;
}
void transformer_en_nombres() { // pas const car on modifie pile ou tableau
std::cerr << "transformer_en_nombres: not yet implemented" << std::endl;
}
void transformer_en_postfixe() { // pas const car on modifie pile ou tableau
std::cerr << "transformer_en_postfixe: not yet implemented" << std::endl;
}
int evaluer_expression() const { // const car a priori on ne modifie ni pile, ni tableau
std::cerr << "evaluer_expression: not yet implemented" << std::endl;
return 0;
}
};
// Fin de postfixe.hpp
int main(){
postfixe<int>::tableau_t tableau0;
postfixe<int> p(tableau0);
p.valider_expression();
p.transformer_en_nombres();
p.transformer_en_postfixe();
p.evaluer_expression();
return 0;
}
Pour le moment si postfixe n'est utilisée que dans ton fichier source principal (main.cpp par exemple) tu peux te contenter de tout mettre dans main.cpp. Mais à terme ta classe devra être transférée dans un fichier (par exemple postfixe.hpp), et main.cpp devra inclure postfixe.hpp. Bonne chance |
Merci sa m'aide sérieusement a comprendre comment les classe template fonctionne il y a juste un dernier petit point ou je suis mêlé.
|
Il y a mieux pour lire une chaine : tu peux utiliser directement un std::string.
#include <iostream>
#include <string>
#include <vector>
int main(){
std::string operation;
std::cout << "opération ? ";
std::cin >> operation;
std::size_t len = operation.size();
std::vector<char> tableau0;
tableau0.reserve(len);
for(std::size_t i=0;i<len;++i) tableau0.push_back(operation[i]);
//...
return 0;
}
Il faut reserver la mémoire quand tu utilises push_back() et quand c'est possible, car un push_back est susceptible de faire un realloc quand le vecteur grossit... c'est mauvais d'un point de vue performance si le vecteur est gros. Pour éviter ce problème on peut utiliser la méthode reserve qui place le vecteur en mémoire de sorte à éviter ces realloc. Un reserve ne modifie pas la taille du vecteur. Une autre possibilité consiste à construire le vecteur directement avec la bonne taille (ou à le resize), mais du coup le vecteur fait la nouvelle taille. Pour plus d'infos sur les vecteurs : http://www.sgi.com/tech/stl/Vector.html Bonne chance |
Ah non ça se fait au niveau du constructeur :
std::vector<int> v(50,0); Sinon tu peux le faire avec std::fill (si tu as redimensionné ton vecteur, ou construit ton vecteur à la bonne taille). Voici un exemple : #include <vector>
#include <iostream>
#include <algorithm> // std::fill
template <typename T>
void write_vector(
const std::vector<T> & v,
std::ostream & out = std::cout
){
const std::size_t n = v.size();
out << '[';
for(std::size_t i=0;i<n;++i){
out << ' ' << v[i];
}
out << " ]" << std::endl;
}
int main(){
std::vector<int> v0(10); // les 10 entiers sont initialisés avec l'entier par défaut (0)
write_vector(v0);
std::vector<int> v(10,1); // les 10 entiers sont initialisés à 1
write_vector(v);
std::fill(v.begin(),v.end(),2);
write_vector(v);
return 0;
}
Ce qui donne à l'exécution : [ 0 0 0 0 0 0 0 0 0 0 ] [ 1 1 1 1 1 1 1 1 1 1 ] [ 2 2 2 2 2 2 2 2 2 2 ] Bonne chance |
Je suis entrain de realiser un programme et j en suis au point qu il me reste une erreur a resoudre pour pouvoir proceder a la compilation.mais je n arrete pas de faire face a cette erreur:"E:\临床医学一\computer\nveau cours et ex\sss\43107139-3-a.cpp(6) : error C2447: missing function header (old-style formal list?)"
|
C'est hors sujet mais pour faire bref de nos jour on utilise <iostream> au lieu de <iostream.h> (obsolète. Du coup les classes de la stl sont dans le namespace std. Ce qui donne :
#include <iostream>
void swap(float *p1,float *p2){
/*
// je ne sais pas ce que tu as voulu faire ici mais ça n'a pas de sens
// la variable p2 est passée en paramètre et est masquée par une variable locale p2
// la boucle while peut tourner à l'infini (du moins jusqu'à faire une seg fault
while(*p1<*p2) p1++;
float *p2=p1;
*/
}
int main( ){
float a,b,c;
std::cout<<"xxxxxxxxxxx";
std::cin >> a >> b >> c;
swap(&a,&b);
swap(&a,&c);
swap(&b,&c);
std::cout << "xxxxxxxxxxxxxxx";
std::cout << a << ' ' << b << ' ' << c << std::endl;
return 0; // code d'exécution du programme
}
Merci d'ouvrir un NOUVEAU sujet pour tout problème différent de celui de départ (post <1>) Bonne chance |