Bonsoir, ayant passé plus d'un an à pisser du Java (me manque encore l'évènementiel à maîtriser), je m'intéresse de plus en plus aux langages de bas niveau comme C ou ASM.
Pensant que la transition serait un peu trop choquante, je compte faire d'abord un petit tour de C++ pour me préparer mentalement.
Comme premier TP que je me suis imposé, j'ai choisi la conception d'une petite calculette interactive :
#include <iostream>
#include <vector>
using namespace std;
class Operation
{
private:
string name;
int inputs[2];
int output;
public:
static vector<Operation> operations;
Operation(int choice, int a, int b)
{
this->inputs[0]=a,
this->inputs[1]=b;
switch(choice)
{
case 1:
this->somme();
this->name="Somme de "+to_string(inputs[0])+" et "+to_string(inputs[1]) ;
break;
case 2:
this->difference();
this->name="Différence de "+to_string(inputs[0])+" et "+to_string(inputs[1]) ;
break;
case 3:
this->produit();
this->name="Produit de "+to_string(inputs[0])+" et "+to_string(inputs[1]) ;
break;
case 4:
this->quotient();
this->name="Quotient de "+to_string(inputs[0])+" et "+to_string(inputs[1]) ;
break;
case 5:
this->reste();
this->name="Reste de "+to_string(inputs[0])+" par "+to_string(inputs[1]) ;
}
}
void somme()
{
this->output = this->inputs[0]+this->inputs[1];
}
void difference()
{
if(this->inputs[0]-this->inputs[1]<0)
{
this->output = this->inputs[1]-this->inputs[0];
}
else
{
this->output = this->inputs[0]-this->inputs[1];
}
}
void produit()
{
this->output = this->inputs[0]*this->inputs[1];;
}
void quotient()
{
this->output = this->inputs[0]/this->inputs[1];;
}
void reste()
{
this->output = this->inputs[0]-((this->inputs[0]/this->inputs[1])*this->inputs[1]);
}
static void interaction0()
{
bool b=true;
while(b)
{
int i=0;
cout<<"1. Nouvelle opération\n";
cout<<"2. Afficher les opérations\n";
cout<<"3. Quitter\n";
cin>>i;
switch(i)
{
case 1:
interaction1();
break;
case 2:
for(int j=0; j<operations.size() ; j++)
{
cout<<operations.at(j).name<<" : "<<operations.at(j).output<<"\n"<<endl;
}
break;
case 3:
b=false;
break;
default:
cout<<"/!\Entrée invalide/!\\"<<endl;
break;
}
}
}
static void interaction1()
{
int input[2];
int choice0;
string menu0[5]={"1. Somme ","2. Difference","3. Produit ","4. Quotient ", "5. Reste "};
string menu1[2]={"a =","b ="};
string quit0 = "6. Quitter";
while(true)
{
for(int i=0; i<5;i++)
{
cout<<menu0[i]<<endl;
}
cout<<quit0<<endl;
cin>>choice0;
if(choice0==6)
{
break;
}
else
{
for(int i=0; i<2; i++)
{
cout<<menu1[i]<<" ";
cin>>input[i];
}
Operation o(choice0, input[0], input[1]);
operations.insert(operations.end(), o);
cout<<"Résultat = "<<o.output<<endl;
}
}
}
};
vector<Operation> Operation::operations ;
int main(int argc, const char * argv[])
{
Operation::interaction0();
return 0;
}
(désolé pour les sauts de ligne)
D'abord j'ai eu une galère avec mon vector statique, je ne savais pas qu'il devait être initialisé en dehors du main (pas besoin en Java).
Ensuite seconde galère : je voulais obtenir la longueur d'un tableau avec une fonction custom mais impossible de passer un tableau en argument, j'ai vu qu'il fallait jouer avec des pointeurs, je suppose que c'est pareil pour tout autre argument n'étant pas un type primitif à part les string ?
D'ailleurs je n'ai ni touché aux pointeurs ni aux références, est-ce que ça m'aurait ajouté un plus ? Comme instancier des objets dynamiques?
Merci au connaisseurs de m'éclairer ![]()
Aussi,
qu'elle est la différence entre ces deux déclarations de main ?
je voulais obtenir la longueur d'un tableau avec une fonction custom mais impossible de passer un tableau en argument, j'ai vu qu'il fallait jouer avec des pointeurs, je suppose que c'est pareil pour tout autre argument n'étant pas un type primitif à part les string
pas vraiment compris la question
D'ailleurs je n'ai ni touché aux pointeurs ni aux références, est-ce que ça m'aurait ajouté un plus ?
Oui, surtout pour les pointeurs vu que ton objectif est de faire notamment du C
Comme instancier des objets dynamiques?
Exactement comme en Java. Si tu veux le supprimer de la mémoire: delete tonObjet
qu'elle est la différence entre ces deux déclarations de main ?
int main()
int main(int argc, const char * argv[])
quand tu mets sous la forme int main(int argc, const char * argv[]), tu dis que tu attends potentiellement des paramètres. argc est ton nombre de paramètres, et argv le nom de chaque paramètre (nom de l'exécutable y compris)
pour determiner la taille d'un tableau alloue de la facon suivante int tableau[] = { 1,2, etc... };
tu fais sizeof(tableau)/sizeof(tableau[0]). sizeof renvoie la taille en byte (octet) de ce que tu passe en parametre, donc c'est la taille totale en memoire de ton tableau divise par la taille en memoire d'une case
pout les tableaux dynamiques (notamment std::vector), ils ont des methodes implementees (la ca sera monVector.size() )
sinon j'ai tres vite fait survole ton code et y'a un truc qui saute aux yeux : tous les "this->". enleve les tous, ca ne sert strictement a rien.
this, c'est un pointeur qui contient l'adresse memoire dans laquelle se trouve l'instance de ta classe. si tu fais un printf(this); ca renverra une valeur en hexidecimal.
dans les methodes d'une classe tu as automatiquement acces a tous ses methodes/attributs membres, il ne faut utiliser this que si tu as besoin d'envoyer quelque part l'adresse de l'instance de ta classe.
ah et du coup tu as effectivement touche aux pointeurs sans le savoir.
la fleche '->' remplace le point '.' pour acceder aux methodes/attributs d'une classe lorsaue tu as un pointeur.
someClass* maClass = new someClass; //on cree le pointeur maClass qui pointe sur une nouvelle instance de someClass fraichement creee
maClass->maMethode(); //appelle une fonction de someClass
*maClass.maMethode();la derniere ligne fait exactement la meme chose que celle d'avant (et produit le meme binaire une fois compile).
utiliser l'etoile '*' avant le nom de la variable pointeur dereference le pointeur, ca permet d'obtenir la classe comme si t'avais pas de pointeur.
tu peux notamment instancier une reference vers maClass en dereferencant un pointeur pour apres pouvoir l'utiliser comme une classe normale
someClass& maReference = *maClass;l'esperluette '&' lors de la declaration d'une variable dit qu'il s'agit d'une reference sur une classe, tandis si tu l'utilise comme suit
someClass maClasse; //cree une nouvelle instance de someClass
someClass* maClass = &maClasse;ca permet d'obtenir l'adresse memoire de la variable.
Le 25 février 2016 à 00:02:15 Candystand a écrit :
Comme instancier des objets dynamiques?
Exactement comme en Java. Si tu veux le supprimer de la mémoire:
delete tonObjet
Quand l'objet n'est plus référencé dans le code il n'est pas censé s'auto-delete ?
Le 25 février 2016 à 00:28:36 kaTk a écrit :
pour determiner la taille d'un tableau alloue de la facon suivanteint tableau[] = { 1,2, etc... };
tu fais sizeof(tableau)/sizeof(tableau[0]). sizeof renvoie la taille en byte (octet) de ce que tu passe en parametre, donc c'est la taille totale en memoire de ton tableau divise par la taille en memoire d'une casepout les tableaux dynamiques (notamment std::vector), ils ont des methodes implementees (la ca sera monVector.size() )
j'ai vu pour le sizeof(), mais disons que je veux créer une fonction
SOMME(int tab[]){
int somme =0;
for(int i=0 ; i<sizeof(tab[])/sizeof(tab[0]);i++){
somme += tab[i];
}
return somme;
}
j'ai testé et ça ne fonctionne pas.
sinon j'ai tres vite fait survole ton code et y'a un truc qui saute aux yeux : tous les "this->". enleve les tous, ca ne sert strictement a rien.
this, c'est un pointeur qui contient l'adresse memoire dans laquelle se trouve l'instance de ta classe. si tu fais un printf(this); ca renverra une valeur en hexidecimal.
dans les methodes d'une classe tu as automatiquement acces a tous ses methodes/attributs membres, il ne faut utiliser this que si tu as besoin d'envoyer quelque part l'adresse de l'instance de ta classe.
je sais que c'est inutile à part quand les paramètres ont les mêmes noms que les attributs mais ça me permet de bien faire abstraction et différencier l'instancié du statique.
Il faut vraiment que je lise sur les pointeurs et références parce qu'à ce niveau je suis perdu, ça doit tellement paraitre évident pour quelqu'un ayant débuté la programmation en langage machine.
avec les raw pointer (pointeur de base, le seul qui existait pendant un bon moment) c'est la gestion de la memoire totalement manuelle. maintenant avec les smart pointer et toutes les nouveautes y'a des feature comme l'auto-delete mais j'ai jamais utilise donc je peux pas t'en dire plus
pour acceder un membre static il faut faire preceder son nom du nom de la classe + "::"
je t'assure que utiliser "this->" c'est vraiment une grosse connerie.
si tu veux savoir quelle variable appartient a qui donne leur des noms specifiques (comme le prefixe m_ http://stackoverflow.com/questions/13018189/what-does-m-variable-prefix-means)
les pointeurs c'est pas evident a comprendre surtout venant d'un langage sans gestion de memoire donc prends bien le temps de t'informer et apprendre sur divers sites.
hint: les references c'est pareil que les pointeurs sauf que le dereferencement se fait automatiquement quand tu l'utilises
<code>maClass->maMethode(); //appelle une fonction de someClass
la derniere ligne fait exactement la meme chose que celle d'avant (et produit le meme binaire une fois compile).
Nope, les deux lignes sont différente (et la deuxième ne compilera même pas) parce que le point « . » est prioritaire sur l'étoile « * », pour obtenir le même résultat tu aurais du écrire (*maClass).maMethode();.
Juste pour le code, pour ajouter un objet operation dans ton vector, tu peux utiliser push_back qui est plus lisible.
Autre point auquel il que faut tu t'interesses en absolue priorité car on est vraiment plus en java ici. C'est la différence entre objets, pointeurs et références. Ce que tu poses dans ton vector ce n'est pas o mais une copie de o, ca coute toujours plus cher que d'utiliser des pointeurs.
En java ce sont des pointeurs cachés avec des compteurs de références, etc, mais en C++ c'est pas pareil du tout. Tu as la maitrise complète de ce qu'il se passe, mais a condition de comprendre comment ca marche en dessous. sinon boum. C'est pour ca que tu dois donner la priorité a la comprehension objet, pointeur, ref, copy constructor.
Il faut que tu comprennes ce que sont les constructeurs par copie et la redéfinition de l'opérateur "=". Car quand tu fais o1 = o, ou push_back(o) c'est une copie bit a bit qui est faite. C'est tres puissant car tu peux gérer completement des déplacement d'objets en mémoire, mais si tu as un objet non copyable ou un pointeur contenu dans o et que tu maitrises pas ces concepts de copy constructor, alors par exemple le delete va supprimer deux fois le même emplacement mémoire et boum. Etc.
Les objets (non pointeurs) sont automatiquement supprimés quand ils sortent de la portée, mais pas les références. Tu peux delete une ref, mais le compilateur ne va pas appeler le destructor en sortie de portée (ce qui fait quand même une petite différence entre objet et référence sur cet objet, sinon ils sont pareils).
Bref, en java tu es sécure (relativement), mais en c++ pas du tout, donc priorité aux tests qui te permettent de comprendre les mecanismes avant de test des calculettes si tu veux mon avis.
Le 25 février 2016 à 00:54:52 VIeRepublique a écrit :
Il faut vraiment que je lise sur les pointeurs et références parce qu'à ce niveau je suis perdu, ça doit tellement paraitre évident pour quelqu'un ayant débuté la programmation en langage machine.
Bof
Après je suis pas une référence en C++ (
) mais je crois qu'un des deux est simplement plus adapté dans certains cas, mais peut être légèrement plus contraignant ?
Enfin j'aurais tendance à utiliser les références en tant qu'argument de fonction, et les pointeurs pour faire de la manipulation en mémoire, si je ne me trompe pas