450

bon, je m'en sort pas avec les stringstream...

J'ai écrit ça :
std::cout << "Anniversaire : " << m_BirthdayDate.stringDate() << std::endl;
Sachant que stringDate() renvoie une std::stringstream, et que je veux la renvoyer sur std::cout.

Un objet Contact contient plusieurs instances de Date.
Je tiens à ce que ce soit la classe Date qui crée la chaine de caractères voulue, et que ce soit la classe Contact qui l'affiche, sans aller récupérer les éléments de l'objet Date un par un via des accesseurs. Je ne sais pas comment m'y prendre...

451

renvoie plutôt un une string. déjà parce que tu peux te servir de ce que te renvoie ta méthode pour autre chose que de l'envoyer dans un stringstream
et puis surtout parce que je ne sais pas comment envoyer un stringstream dans un autre stringstream triroll
(ton truc ça ne t'affiche pas une adresse ? Parceque la dernière fois que j'avais essayé, ça m'affichait ça au lieu du contenu du stringstream gol)

pour ton problème, la classe Date peut renvoyer une string, donc il te faut une méthode stringContact() dans contact qui appelle les méthodes stringDate de chacun de ses membres date, qui les concatène et qui renvoie le résultat. après tu n'as plus qu'à fait std::cout << contact.stringContact() << std::end;
avatar

452

aze (./451) :
(ton truc ça ne t'affiche pas une adresse ? Parceque la dernière fois que j'avais essayé, ça m'affichait ça au lieu du contenu du stringstream gol.gif )

Faudrait déjà que ça compile gni
aze (./451) :
pour ton problème, la classe Date peut renvoyer une string, donc il te faut une méthode stringContact() dans contact qui appelle les méthodes stringDate de chacun de ses membres date, qui les concatène et qui renvoie le résultat. après tu n'as plus qu'à fait std::cout

C'est justement ce que je veux éviter, parce que si je modifie la classe Date, j'ai une chance sur deux de foutre en l'air Contact. Et j'ai pas envie de spécifier x accesseurs à Date et d'avoir après à m'y tenir.
C'est pour ça que je veux que Date me construise une std::string avec ses éléments, et là je coince...

453

Personnellement j'ai même pas du tout compris le problème, tu peux expliquer autrement stp ? grin
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

454

Ok. grin

J'ai une classe Date : int année, int mois, int jour
J'ai une classe Contact qui contient entre autre trois Dates

Je veux que la classe Date ait une méthode stringDate() qui me renvoie une std::string genre "3 février 2000".
Je veux que la classe Contact n'ait que ça à faire pour afficher une Date : cout << dateX.stringDate()
Je ne veux pas que la classe Contact fasse ça : cout << dateX.getDay() << dateX.getMonth() << dateX.getYear()

C'est mieux ? smile

455

pourquoi contact doit il afficher des choses?

en effet, construits une string dans ta classe date, et utilise cette méthode (toString()?) dans ta classe contact smile

je verrais bien aussi un toString() dans ta classe contact, pour afficher uniquement dans main ou la classe qui sert à l'affichage.

456

En fait, je fais une méthode dispContact() qui affiche toutes les infos d'un contact (nom prénom etc...) et aussi les dates qui lui sont relatives via stringDate().

Mais j'ai pas reposé la question de mon problème :
Comment, à partir de trois int, créer une string ? C'est là que Zephyr m'a parlé de streamstring, mais je m'en sort pas avec...

457

streamstring d'après son nom c'est un objet qui se comporte comme un stream mais tu peux en récupérer le contenu sous forme de string.

je vois pas bien l'intéret face à de simples concaténations.

Y'a pas de C++doc?

458

squalyl (./457) :
mais tu peux en récupérer le contenu sous forme de string

C'est bien là que je coince grin

459

[nosmile]
class Date
{
private:
  int année, mois, jour;
public:
  std::string toString(void) const
  {
	  std::stringstream ss; // stringstream pour convertir des ints en string
	  ss << jour << "/" << mois << "/" << année; // conversion simple en string, je te laisse faire la version en lettres ^^
	  return ss.str();
  }
};

class Contact
{
private:
	Date date1, date2;
public:
	std::string toString(void) const
	{
		return date1.toString() + " " + date2.toString(); // pas besoin de stringstream, on concatène juste des strings
	}
	void dispContact(void) const
	{
		std::cout << toString() << std::endl;
	}

};


l'intéret de stringstream c'est qu'il y a l'operateur << qui est défini pour les types de base et qui sert à convertir ce type en string. donc en général on utilise un stringstream pour construire une chaine à partir de types qui ne sont pas forcément des strings.
la concaténation ne marche qu'entre strings

sinon je ne te conseille pas vraiment d'inclure la méthode d'affichage comme membre de ta classe, mais juste de te contenter d'une méthode de conversion en string. après une solution encore meilleure est de surcharger l'operateur << mais c'est pas forcément simple, donc on peut se contenter d'une méthode toString () smile
avatar

460

heu mais pourquoi utiliser stringstream ici ? je te l'avais suggéré pour convertir des strings en int, mais pas l'inverse ^^ tu ne peux pas tout simplement utiliser l'opérateur "+" pour concaténer des std::strings et des ints entre eux ?

[edit] en fait je raconte n'importe quoi, + n'est pas défini en C++ entre les strings et les ints, c'est vrai dans plein de langages mais pas ici. en revanche tu peux utiliser des "ostream" au lieu de "stringstream", ce qui sera plus adapté à ton cas je pense.

si tu veux utiliser des streamstring, tu as la méthode ".str ()" qui te donne un std::string contenant tout ce que tu as "poussé" dans le streamstring.

(sinon effectivement surcharger l'opérateur << c'est plus joli, ça permet de faire des std::cout << maDate << std::endl)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

461

Merci à tous, je viens de trouver et d'implémenter et ça marche \o/
Je suis en fait passé par la classe ostringstream, et en effet la méthode .str() ^^ :
std::string Date::stringDate()
{
    std::string stdstr;

    if (isDateSet())
    {
        std:: ostringstream osstr;
        osstr << m_Day << " " << monthString(m_Month) << " " << m_Year;
        stdstr = osstr.str();
    }
    else
        stdstr = "non renseigné";

    return stdstr;
}


Et ok, je vais surcharger l'opérateur <<, pour le fun. Puis si vous dites que c'est plus classe ... grin

462

squalyl (./455) :
pour afficher uniquement dans main ou la classe qui sert à l'affichage.

J'aimerais bien que tu me reparles de ça stp. smile

Autant je vois bien les classes en tant que conteneurs de données ayant leur propre, autant je ne vois pas en quoi une classe peut me servir à l'affichage. Parce que ça ne fait qu'exécuter des actions (affiche ça ici, ça là etc...), c'est donc quelque chose de très impératif. Je me représente mal comment je pourrais utiliser une classe pour afficher.

Merci d'avance. smile

463

bin l'idée c'est que les classes sont des conteneurs, oué, donc justement moi j'ai jamais vu un container qui parle. grin A part le debug, un objet ne doit rien écrire.
Tout doit être fait soit dans main, soit dans des classes dont le but est la communication. Pourquoi contact devrait il écrire sur stdout alors que peut être cette classe communiquera par réseau, donc socket, ou plus simplement fichier?
du coup il vaut mieux déporter / modulariser les E/S.

464

T'as raison. Je fais donc faire que Contact renvoie aussi une chaine qui sera affichable ou inscriptible dans un fichier (et c'est bien mon but de toute façon, sauvegarder et afficher). Merci. smile

465

466

squalyl (./463) :
soit dans des classes dont le but est la communication

re-come-back à nouveau grin

C'est quoi le principe d'une classe dédiée à la communication ? Je vois pas ce que ça peut donner ^^

467

bah juste regrouper ce qui fait l'affichage. Tu fais pas d'ihm donc main et cout peuvent suffire ^^

468

Mais que devrais-je avoir comme type de classe ?
un truc qui récupère auprès d'une classe ses différentes chaines, puis les affiche ? Ca constitue des fonctions ça, pas des données, donc pas une classe, si ?

469

pour moi un classe sert aussi a regrouper des fonctions qui ont un thème commun, en général travailler sur les données d'une classe justement, mais aussi pourquoi pas pour autre chose.

on va sans doute me contredire mais je verrais bien une classe qui est capable d'écrire tous les objets de ton projet dans un fichier, sur stdout, etc, sur un stream en général.

ça s'appelle un "writer". c'est un machin qui write cheeky

ça ferait
main()
{
stdwriter thewriter(std::cout)
thewriter.write(une instance de date).
etc
}

le constructeur du writer prend en argument un "output stream" quelconque, dont std::cout (je sais pas le vrai nom de la classe) est une sous classe, ostringstream aussi, etc

et selon le stream que tu files a ton writer il devient capable d'écrire n'importe ou.

y'a sans doute d'autres méthodes, comme ne pas utiliser ce truc du tout et faire tous tes affichages a base de cout<<plop dans le fichier principal ^^

470

[edit] pas raffraichi la page sorry
Je vois pas trop ce que veut dire squalyl. Par contre surcharger l'opérateur << ça te permet de manipuler directement ta classe avec les entrées-sorties, donc tu pourras en principe les envoyer sur le réseau, puisque tu auras designé tes classes de communication réseau comme étant des i/ostream wink
Une bonne pratique quand tu fais un objet si tu veux pouvoir les sauvegarder dans un fichier c'est de surcharger les opérateurs << ("exportation") et >> ("importation"). S'il s'agit de l'affichage et la saisie tu peux aussi faire via chaîne mais d'un point de vue C++ c'est moins joli:
class Date {
	int d, m, y;
public:
	// Construction "classique"
	Date(int day, int month, int year)
		: d(day), m(month), y(year) {}
	// Construction à partir d'une chaîne ("importation")
	Date(string s) {
		const char *pt = s.c_str();
		d = atoi(pt);
		if (pt = strchr(pt, '/')) {
			m = atoi(++pt);
			if (pt = strchr(pt, '/')) {
				y = atoi(++pt);
				return;
			}
		}
		throw "Le format de la chaîne est incorrect (dd/mm/yyyy)";
	}
	// Conversion en chaîne ("exportation")
	operator string() {
		char str[10*3+3];
		sprintf(str, "%02i/%02i/%04i", d, m, y);
		return str;
	}
};

Je te conseille pas ce code qui est ignoble hein. Mais je pense qu'à partir de là tu peux voir l'intérêt de surcharger <</>> et d'utiliser des i/ostream, qui donneraient un code 1000x plus propre et symétrique pour la lecture/écriture.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

471

en effet, Brunni a raison, le writer est l'équivalent java de l'opération << en c++.

Surcharge l'opérateur << de tes classes et sers toi de ça dans main.

472

Merci pour toutes vos idées. Je suis vraiment loin de tous ces concepts, faut que j'y arrive. smile

PS -> quelle différence entre surcharger << et utiliser toString() (que j'ai implémentée) ?

473

toString ça vient de Java (inutile de continuer ce paragraphe avec une opinion personnelle cheeky), en C++ ce serait plutôt l'opérateur string (conversion implicite vers string). Cela dit c'est plus propre d'avoir une méthode qui fait la conversion comme toi.
La grosse différence c'est comment dire... tout dépend de ce que tu préfères; soit tu dois faire:
// Utilisation plus simple
Date d;
cout << (string)d << endl;    // Plus lent
string str = d;    // Tout simple et pratique!

// Implémentation de la conversion plus complexe!
operator string() {
    ostringstream oss;
    oss << d << '/' << m << '/' << 'y';
    return oss.str();
}


Si tu surcharges l'opérateur <<:
// Utilisation plus complexe en dehors des E/S
Date d;
cout << d << endl;    // Simple
ostringstream oss;    // Pas simple pour l'avoir sous forme de chaîne
oss << d;
string s = oss.str();

// Implémentation de l'opérateur simple
ostream operator << (ostream &os, Date d) {
    return os << d << '/' << m << '/' << y;
}
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

474

Effectivement, c'est la première méthode que j'ai implémentée. Alors à moins que vous n'y voyiez une hérésie à la POO, je resterai dessus, pour rester simple au début. N'oubliez pas que c'est mon premier programme, je suis déjà à fond dans mes capacités trioui

475

Ca va très bien, mais ton "prof" Claude il risque de te dire le contraire grin
Bref te fais pas de souci pour ça, c'est une question de préférence personnelle; tu verras bien wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

476

Link (./428) :
On voit mieux les détails en C++/CLI, qui utilise des pin_ptr<> pour empêcher un objet managé de bouger lors de la réorganisation (et je crois que c'est un wrapper de GCHandle::Alloc(GCHandleType::Pinned)).

C'est comme HLock, quoi. smile
Link (./437) :
Par ailleurs, dans les compilos où la RTTI est désactivable, soit le switch RTTI-off ment, soit les exceptions ne marchent pas; car l'identification d'exceptions C++ nécessite de la RTTI, on ne peut (à ma connaissance) la faire en statique.

Dans les systèmes d'exceptions qui utilisent un unwinder (genre DWARF, utilisé sous GNU/Linux), c'est possible en général sans RTTI. (En revanche, c'est le dépilement (unwinding) qui est "runtime".) Les informations d'unwinding te disent non seulement comment dépiler et quels destructeurs appeler (une sorte de bytecode VM exécuté par l'unwinder), mais aussi où se trouvent des try et quels types ils attendent. Or, le throw sait dès la compilation (sauf dans un cas décrit dans le prochain paragraphe) de quel type est la variable qu'on lui passe. Du coup, le compilateur peut générer du code qui passe ce type statique à l'unwinder, qui n'a ensuite plus qu'à comparer ce type avec ce qu'attendent les blocs try. Ce n'est pas équivalent à du RTTI parce qu'on n'a pas besoin d'identifier le type d'un objet en temps d'exécution, donc les objets n'ont pas besoin de porter l'overhead pour l'identification de leur type, seul l'unwinder a besoin de certaines connaissances sur les types. Donc il n'y a pas d'overhead par objet.

Maintenant, pourquoi ai-je dit "en général"? Bah, parce que quelqu'un pourrait s'amuser à faire du throw avec des pointeurs, et du coup le type runtime n'est pas forcément connu en temps de compilation. Mais du coup, je suppose que ce qui va se passer avec -fno-rtti, c'est que l'exception en question ne sera pas attrappée. Mais là c'est vraiment le problème du programmeur. Faut pas lancer des pointeurs comme exceptions en C++, et encore moins des pointeurs polymorphes si on a désactivé le RTTI. wink
Folco (./440) :
Tiens, ma classe DateException, je l'ai déclarée comme ça :
class DateException
{
    public:

    DateException(const std::string & error);
    ~DateException();
    std::string getErrorString();


    private:

    std::string m_ErrorString;
};
C'est bien ou pas ? J'ai pas eu l'impression que c'était dans vos idée de faire les choses...
Uther (./441) :
Personnellement j'aurais fait pareil

Personnellement j'aurais lancé un const char * (voire un int à la AMS), mais bon. grin
GoldenCrystal (./443) :
puis retourne un const std::string& sur cet objet

Euh, retourner un const & est dangereux et absolument déconseillé. Comme l'explique krazy2, l'outil utilisé par KDE pour détecter le code sale: For binary compatibility reasons avoid const references for return types. For example, "const QList<int> &someProperty() const" should be rewritten to return a value instead, eg "QList<int> someProperty() const". See <http://techbase.kde.org/Policies/Library_Code_Policy#Const_References> for more details. En gros, si tu retournes un const &, tu ne peux pas créer l'objet dynamiquement dans la fonction (parce que si tu le crées sur la pile, il sera détruit trop tôt, si tu le crées dans le tas, tu leakes de la mémoire), il faut l'avoir dans la classe, donc ça fixe une contrainte à l'implémentation, donc tu ne peux pas modifier ton code après sans casser la compatibilité binaire. De plus, si la classe appelante garde la référence au lieu de la recopier (ce qui ne donnera aucun warning si la valeur a été retournée par référence), elle peut se retrouver avec une valeur modifiée.

Cela dit, je comprends pourquoi tu fais ça avec std::string, c'est bien le problème des classes qui ne sont pas implicitement partagées, tu contournes une erreur de design de std::string là. Avec QString, retourner une valeur ne serait pas si coûteux.
squalyl (./447) :
non c'est le constructeur qui throw l'exception, que tu testes ou pas avant.

pour que ton truc soit utile il faudrait que le constructeur lance une sousclasse de RuntimeException au lieu d'une IOException qu'il faut catcher.

Tester avant n'est pas suffisant, cf. race condition (en particulier: TOCTOU – Time Of Check vs. Time Of Use). De plus, un test d'existence du fichier n'est pas suffisant pour garantir une ouverture avec succès.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

477

Kevin Kofler (./476) :
Personnellement j'aurais lancé un const char * (voire un int à la AMS), mais bon.

Quand j'ai commencé à lire le chapitre des exceptions, c'est ce que je me suis dit que je ferais. D'ailleurs, je vois pas pourquoi ça serait pas bien. j'ai lancé une référence à un objet parce que partout, j'ai lu et on m'a dit que c'était bien. grin

478

C'est pour faire plus "java-style". En java tu ne lances jamais d'entiers ou autres, c'est toujours un type dérivé de Exception. Ca a l'avantage d'avoir des méthodes standard que tu as sur toutes les exceptions comme le stacktrace, le message associé, le type exact de l'exception, etc.
Même en C++, on code souvent comme ça, genre tu fais ton type Exception à la main et tu lances des sous types de Exception via l'héritage (garde ça pour plus tard si tu l'as pas encore vu).
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

479

Si si j'ai vu l'héritage, polymorphisme et fonctions virtuelles, mais dans une classe aussi bête (telle que je l'ai écrite), je saurais pas quoi en faire ^^

480

Euh, ça existe en C++ operator string ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »