Probleme creation classe
Fermé
clem
-
10 juin 2017 à 22:00
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 15 juin 2017 à 10:02
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 15 juin 2017 à 10:02
A voir également:
- Probleme creation classe
- Creation compte gmail - Guide
- Création compte google - Guide
- Media creation tool - Télécharger - Systèmes d'exploitation
- Création site web - Guide
- Création groupe whatsapp - Guide
4 réponses
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 12 juin 2017 à 10:12
Modifié le 12 juin 2017 à 10:12
Bonjour,
Comme le dit probablement ton compilateur :
Personnellement je déclarerais le bloc privé en début de classe (j'aime bien savoir ce que contient une classe avant de voir ses méthodes), même ce n'est pas obligatoire.
Tu peux utiliser un
Vu que collidepoint ne modifie pas l'objet, tu peux rajouter le mot clé
Tu as oublié le retour à la ligne (
Enfin le
Note que l'initialisation du vecteur à pu se faire comme un tableau. Toutefois, cette syntaxe peut ne pas être prise si tu n'as pas un compilateur récent. Dans ce cas, tu peux initialiser les cases une à une :
Bonne chance
Comme le dit probablement ton compilateur :
(mando@velvet) (~) $ g++ plop.cpp
plop.cpp: In constructor ‘Rect::Rect(int*)’:
plop.cpp:8:15: error: incompatible types in assignment of ‘int*’ to ‘int [4]’
m_rect(rect)
Personnellement je déclarerais le bloc privé en début de classe (j'aime bien savoir ce que contient une classe avant de voir ses méthodes), même ce n'est pas obligatoire.
Tu peux utiliser un
std::vector<int>à la place.
Vu que collidepoint ne modifie pas l'objet, tu peux rajouter le mot clé
constdevant l'accolade, c'est plus propre. Enfin en C les méthodes par conventions nommés sous l'une de ces deux formes
ma_methodeou
maMethode.
Tu as oublié le retour à la ligne (
std::endl)
Enfin le
using namespace std;est à mon avis au début une mauvaise habitude. En fait tant que tu es dans un .cpp pas de problème, par contre le jour où tu écris un header (.hpp) il ne faut pas en utiliser.
#include <iostream> #include <vector> #include <cassert> class Rect { private: std::vector<int> m_rect; public: Rect(const std::vector<int> & rect): m_rect(rect) { assert(rect.size() == 4); } bool collide_point(int ptx, int pty) { for (int x= m_rect[0]; x <= m_rect[2]; x++) const { if (x == ptx) { for (int y= m_rect[1]; y <= m_rect[3]; y++) { if (y == pty) { return true; } } } } return false; } }; int main() { std::vector<int> rectangle = {0, 0, 20, 20}; Rect sprite(rectangle); std::cout << sprite.collide_point(5, 2) << std::endl; return 0; }
Note que l'initialisation du vecteur à pu se faire comme un tableau. Toutefois, cette syntaxe peut ne pas être prise si tu n'as pas un compilateur récent. Dans ce cas, tu peux initialiser les cases une à une :
std::vector<int> rectangle(4); rectangle[0] = 0; rectangle[1] = 0; rectangle[2] = 20; rectangle[3] = 20;
Bonne chance
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 13 juin 2017 à 10:02
Modifié le 13 juin 2017 à 10:02
Est-ce-que cassert fonctionne comme une assertion python ?
Les assertions fonctionnent comme en python, elles provoquent une erreur si le test n'est pas vérifié.
Il y a toutefois quelques différences. En python, tu peux préciser le message d'erreur, et tu peux rattraper avec un
Chose intéressante par contre, passer l'option
Et pourquoi ne pas utiliser des tableaux statiques ?
Tu peux mais dans ce cas il tu n'as pas d'opérateur
... en vrai tu dis :
- crées un bloc statique de 4 entiers
- initialise le avec les valeurs 1;2.3.4
- mémorise l'adresse de ce bloc de 4 entiers dans
- donc
Ainsi si tu écris ensuite
En conséquence, si ensuite tu fais
Du coup, pour faire une recopie d'un tableau statique, il faudrait passer par une fonction du genre
Juste pour obtenir la taille (je crois qu'on est obligé de passer par un for pour les statiques non? ) ?
Comme le montre le code ci-dessus, la syntaxe des
Le seul intérêt du
Bonne chance
Les assertions fonctionnent comme en python, elles provoquent une erreur si le test n'est pas vérifié.
Il y a toutefois quelques différences. En python, tu peux préciser le message d'erreur, et tu peux rattraper avec un
try ... exceptl'exception levée par l'assertion. Ce n'est pas le cas avec
asserten C/C++, car cette fonction vient du C, donc elle n'a ni paramètre optionnel (le message d'erreur), et ne lève pas d'exception (notion qui n'existe pas en C), elle provoque juste un arrêt abrupt du programme.
Chose intéressante par contre, passer l'option
-DNDEBUGà la compilation permet de compiler le programme comme si tous les assertions étaient commentés. C'est une des raisons pour lesquelles un assert en C ne doit jamais contenir du code qui modifie une variable, ni de tests qui ont du sens dans une exécution "normale" (par exemple tester si une zone mémoire a été bien allouée). En C/C++ les assertions doivent plus être vus comme des filets de sécurité pour le programmeur et qui sont sensées être tout le temps vérifiées.
Et pourquoi ne pas utiliser des tableaux statiques ?
Tu peux mais dans ce cas il tu n'as pas d'opérateur
=. Un tableau statique n'est pas la meilleure manière de comprendre ce qui se passe. Quand tu écris :
int tab[4] = {1,2,3,4}
... en vrai tu dis :
- crées un bloc statique de 4 entiers
- initialise le avec les valeurs 1;2.3.4
- mémorise l'adresse de ce bloc de 4 entiers dans
tab
- donc
tabest une adresse (un pointeur) de type
int *, qui vaut mettons
0x00123ab.
Ainsi si tu écris ensuite
int * p = tab, tu recopies l'adresse
0x00123abdans p. Ce qui signifie que tu n'as pas recopié le bloc de 4 entiers. Si ensuite tu évalues ce qui est à cette adresse avec l'opérateur
[]ou l'opérateur
*tu vas donc examiner la même zone mémoire. Dans l'algèbre des pointeurs
*(tab +i)équivaut à
tab[i]. Le type du pointeur, ici
int *, permet de correctement donner un sens à ces opérateurs (i.e. se placer au bon endroit et lire le bon nombre d'octets).
En conséquence, si ensuite tu fais
p[2] = 7;,
tab[2]est aussi modifié (puisqu'il s'agit de la même zone.
Du coup, pour faire une recopie d'un tableau statique, il faudrait passer par une fonction du genre
memcpy, ou, moins rapide mais équivalent, recopier case par case le premier tableau dans le second.
#include <cstring> #include <iostream> int main() { int tab[4] = {1,2,3,4}; int p[4]; memcpy(p, tab, 4 * sizeof(int)); for (int x : tab) std::cout << x << std::endl; for (int x : p) std::cout << x << std::endl; return 0; }
Juste pour obtenir la taille (je crois qu'on est obligé de passer par un for pour les statiques non? ) ?
Comme le montre le code ci-dessus, la syntaxe des
:permet de s'en sortir sans la taille. Si cette syntaxe n'est pas supportée (typiquement sur les compilateurs un peu anciens), tu peux toujours écrire une boucle
for(unsigned i = 0; i < 4; ++i) { ... }.
Le seul intérêt du
std::vector<int>est ici d'avoir accès à une syntaxe plus dans l'esprit de python, même si cela induit un léger surcoût par un rapport un tableau statique.
Bonne chance
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
14 juin 2017 à 09:29
14 juin 2017 à 09:29
Je pense que la notion la plus "nouvelle" par rapport au python est vraiment la notion de pointeur (= adresse). Tout objet a une adresse. Par contre selon son type il occupe plus ou moins de taille en mémoire. C'est ce qui conduit à typer les adresses, afin de caractériser la zone pointée. Ensuite c'est juste une gymnastique à prendre entre l'adresse et ce qui se trouve à cette adresse.
Est-ce que ton problème est résolu ?
Est-ce que ton problème est résolu ?
Oui merci bezucoup encore une fois. Entre temps j'ai divisé la classe (.h et .cpp), j'ai rajouté par exemple colliderect pour tester si deux rectangle se touchent et jai une fonction operator<< qui marche. Maintenant je dois vraiment apprendre comment utiliser adresse et pointeur et faire attention à ne pas confondre adresse et référence. J'ai bien compris les principes mais c'est en pratique où je bloque un peu. À part ca je trouve ça très dommage qu'il n'y ai pas moyen de try except ou de lever une exeption. Dans ma tête je me dis qu'il suffit de créer cette fonction dans un genre de module / biblio mais je n'ai pas vraiment de vision générale d'un langage de programation. En gros comment ça fonctionne vraiment, le derrière des choses. Si les limites sont fixées par l'os, comment, comment est fait un os, qu'en est-t-il de lz sécurité... Bref, beaucoup de choses qui me prendront bc de temps.
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
14 juin 2017 à 22:50
14 juin 2017 à 22:50
Oui merci beaucoup encore une fois. Entre temps j'ai divisé la classe (.h et .cpp).
Bien ! Du moment qu'une méthode n'est pas
J'ai rajouté par exemple colliderect pour tester si deux rectangle se touchent et jai une fonction operator<< qui marche.
Si cet opérateur est bien écrit il est de la forme :
Maintenant je dois vraiment apprendre comment utiliser adresse et pointeur et faire attention à ne pas confondre adresse et référence.
Conceptuellement les deux notions sont proches. La principale différence est qu'une référence est initialisée sur un objet instancié. Un pointeur peut ne pas être initialisé, ou être initialisé à
Je t'invite à lire cette explication :
https://forums.commentcamarche.net/forum/affich-27614885-c-est-quoi-la-difference-entre-passage-par-reference-et-passage#1
J'ai bien compris les principes mais c'est en pratique où je bloque un peu.
Si tu peux être plus précis je pourrai peut-être t'éclairer.
À part ca je trouve ça très dommage qu'il n'y ai pas moyen de try except ou de lever une exeption.
On s'est mal compris. En C/C++ une assertion ne lève pas d'exception. En C la notion d'exception n'existe pas, mais elle existe en C++. Tu peux définir des héritages entre tes classes d'exception et les rattraper différemment une exception selon son type, exactement comme en python.
Dans ma tête je me dis qu'il suffit de créer cette fonction dans un genre de module / biblio mais je n'ai pas vraiment de vision générale d'un langage de programmation.
Oui tu pourrais tout à fait définir une assertion qui lève une exception :
En gros comment ça fonctionne vraiment, le derrière des choses. Si les limites sont fixées par l'os, comment, comment est fait un os, qu'en est-t-il de la sécurité...
Un OS c'est un vaste sujet :) Mais peut être que plonger dans linux t'éclairerait, l'avantage étant qu'une grande partie est codée en C et est open source.
Bref, beaucoup de choses qui me prendront bc de temps.
Oui :-)
Bien ! Du moment qu'une méthode n'est pas
templateelle est sensée être effectivement implémentée dans le fichier .cpp ou être précédée du mot clé
inline.
J'ai rajouté par exemple colliderect pour tester si deux rectangle se touchent et jai une fonction operator<< qui marche.
Si cet opérateur est bien écrit il est de la forme :
#include <ostream> std::ostream & operator << (std::ostream & os, const Rect & r) { os << ... ; return os; }
Maintenant je dois vraiment apprendre comment utiliser adresse et pointeur et faire attention à ne pas confondre adresse et référence.
Conceptuellement les deux notions sont proches. La principale différence est qu'une référence est initialisée sur un objet instancié. Un pointeur peut ne pas être initialisé, ou être initialisé à
NULL.
Je t'invite à lire cette explication :
https://forums.commentcamarche.net/forum/affich-27614885-c-est-quoi-la-difference-entre-passage-par-reference-et-passage#1
J'ai bien compris les principes mais c'est en pratique où je bloque un peu.
Si tu peux être plus précis je pourrai peut-être t'éclairer.
À part ca je trouve ça très dommage qu'il n'y ai pas moyen de try except ou de lever une exeption.
On s'est mal compris. En C/C++ une assertion ne lève pas d'exception. En C la notion d'exception n'existe pas, mais elle existe en C++. Tu peux définir des héritages entre tes classes d'exception et les rattraper différemment une exception selon son type, exactement comme en python.
#include <stdexcept> int main() { try { raise std::runtime_error("plop"); } catch(MonException & e) { // ... } catch(...){ // Rattrape toutes les exceptions non rattrapées // ... } return 0; }
Dans ma tête je me dis qu'il suffit de créer cette fonction dans un genre de module / biblio mais je n'ai pas vraiment de vision générale d'un langage de programmation.
Oui tu pourrais tout à fait définir une assertion qui lève une exception :
class MonException {}; inline MonException mon_assert(bool b) { #ifndef DNDEBUG if (!b) throw MonException(); #endif }
En gros comment ça fonctionne vraiment, le derrière des choses. Si les limites sont fixées par l'os, comment, comment est fait un os, qu'en est-t-il de la sécurité...
Un OS c'est un vaste sujet :) Mais peut être que plonger dans linux t'éclairerait, l'avantage étant qu'une grande partie est codée en C et est open source.
Bref, beaucoup de choses qui me prendront bc de temps.
Oui :-)
Ah! super stdexcept alors. Oui merci je lirais l'explication demain (j'ai mon bac cet aprem :$). D'ailleurs j'ai voulu remplacer mes arrays statiques par des vecteurs, mais ça ne fonctionne pas... La console me dit seulement No Ouput alors je suis pas très éclairé... Pour ne pas copier 80lignes de codes je met juste le header de rect et le main.
Pour le ostream comme tu le vois j'ai utilisé l'amitié pour ne pas avoir à créer une méthode print(), j'espère que c'est une bonne idée :).
Mais peut être que plonger dans linux t'éclairerait,
Je n'ai pas d'ordi en fait :/ je pense que je defilerai juste les pages wikipedia...
#include <iostream>
#include <vector>
using namespace std;
// Rect.h
class Rect
{
public:
Rect(int, int, int, int);
~Rect();
friend std::ostream& operator<<(std::ostream&, Rect const&)
;
bool collidepoint(int, int) const;
bool colliderect(Rect const&) const;
bool collideany(std::vector<Rect> const&) const;
private:
//int* m_rect = new int[4];
std::vector<int> m_rect(4);
};
// -------------- //
int main() {
Rect r(0, 0, 20, 20), a(10, 10, 5, 5), c(21, 80, 6, 8), b(10, 11, 12, 9);
cout << a << endl;
vector<Rect> group;
group.push_back(&a);
group.push_back(&b);
group.push_back(&c);
cout << group[0] << endl;
//cout << r.collideany(group) << endl;
return 0;
}
// -------------- //
Pour le ostream comme tu le vois j'ai utilisé l'amitié pour ne pas avoir à créer une méthode print(), j'espère que c'est une bonne idée :).
Mais peut être que plonger dans linux t'éclairerait,
Je n'ai pas d'ordi en fait :/ je pense que je defilerai juste les pages wikipedia...
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
15 juin 2017 à 10:02
15 juin 2017 à 10:02
Voici un code fonctionnel.
La première erreur est d'avoir précisé la taille dans la déclaration du vecteur interne à la classe Rect. C'est le constructeur qui se charge de ça, pas la déclaration.
Ensuite pour l'affichage, vu que tu te reposes sur des
De la même manière, tu pourrais définir des opérateurs
Bonne chance
#include <iostream> #include <vector> class Rect { private: std::vector<int> m_rect; public: Rect(int a, int b, int c, int d) { m_rect = {a, b, c, d}; } const std::vector<int> & get_vector() const { return m_rect; } }; template <typename T> std::ostream & operator << (std::ostream & os, const std::vector<T> & v) { os << '['; for (auto x : v) os << ' ' << x; os << " ]"; return os; } std::ostream & operator << (std::ostream & os, const Rect & r) { os << r.get_vector(); } int main() { Rect r(0, 0, 20, 20), a(10, 10, 5, 5), c(21, 80, 6, 8), b(10, 11, 12, 9); std::cout << a << std::endl; std::vector<Rect> rectangles = {r, a, b, c}; std::cout << rectangles << std::endl; return 0; }
La première erreur est d'avoir précisé la taille dans la déclaration du vecteur interne à la classe Rect. C'est le constructeur qui se charge de ça, pas la déclaration.
Ensuite pour l'affichage, vu que tu te reposes sur des
std::vector, aussi bien pour stocker les coordonnées d'un rectangle que ton groupe de rectangle, on va directement implémenter un opérateur
<<générique sur les vectors. Attention les méthodes templates doivent toujours être écrites soit dans un header, soit dans l'unique fichier cpp qui l'utilise. Ici je ne l'utilise que dans "main.cpp" donc pas de question à se poser, je peux le mettre directement dans main.cpp.
De la même manière, tu pourrais définir des opérateurs
<<sur tous les containers de la STL (donc
std::set<T>, std::list<T>, std::map<K, V>, etc) si le besoin s'en faisait sentir, et tous les implémenter dans un fichier à part (mettons
stl_io.hpp).
(mando@velvet) (~) $ g++ plop.cpp
(mando@velvet) (~) $ ./a.out
[ 10 10 5 5 ]
[ [ 0 0 20 20 ] [ 10 10 5 5 ] [ 10 11 12 9 ] [ 21 80 6 8 ] ]
Bonne chance
Modifié le 12 juin 2017 à 18:57
Est-ce-que cassert fonctionne comme une assertion python ? (renvoie assertion error) Et pourquoi ne pas utiliser des tableaux statiques ? Juste pour obtenir la taille (je crois qu'on est obligé de passer par un for pour les statiques non? ) ?
Désolé de te poser autant de questions :p :$
Ps - je code sur mobile alors j'ai que un .cpp