[C++] Debug Error

Résolu/Fermé
Utilisateur anonyme - 17 déc. 2007 à 20:22
mamiemando Messages postés 33076 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 17 avril 2024 - 8 janv. 2008 à 22:52
Bonsoir,
C’est la deuxième fois aujourd’hui qu’on me fait sortir un debug error et je ne vois pas pourquoi. Le IDE réclame que j’ai une variable non définie, alors que je l’ai définie déjà !
Au moment de la compilation, aucune erreur n’est déclarée.
Voilà mon fichier .cpp :
#include"complexe.h"
using namespace std;

void complexe::init_complexe(float reel, float imag)
{
	reel=0;
	imag=0;
}
complexe complexe::MultiplierR(float r)
{
	complexe c;
	c.reel*=r;
	return c;
}
complexe complexe::MultiplierC(complexe c)
{
	complexe c1;
	c.reel*=c1.reel*c.reel - c.imag*c1.imag;
	c.imag=c.reel*c1.imag - c.imag*c1.reel;
	return c;
}
complexe complexe::AdditionnerR(float r)
{
	complexe c;
	c.reel+=r;
	return c;
}
complexe complexe::AddionnerC(complexe c1)
{
complexe c;
c.reel=c.reel+c1.reel;
c.imag=c.imag+c1.imag;
return c;
}
complexe complexe::DiviserC(complexe c1)
{
return c1;
}
void complexe::affich()
{
	complexe c;
	cout<<" "<<reel<<"+"<<imag<<"i"<<endl;
};


Et l’imprim-écran du bug :
https://www.cjoint.com/?mruubVtwHc


Bonne soirée et merci d’avance :)


7 réponses

mamiemando Messages postés 33076 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 17 avril 2024 7 748
17 déc. 2007 à 21:32
Il nous faudrait le contenu de complexe.h et la fonction main.

Bonne chance
0
Utilisateur anonyme
17 déc. 2007 à 21:51
Salut,
complexe.h :
#include<iostream>
class complexe
{
private :
	float reel;
	float imag;
public :
	void init_complexe(float, float);
	complexe MultiplierR(float);
	complexe MultiplierC(complexe);
	complexe AdditionnerR(float);
	complexe AddionnerC(complexe);
	complexe DiviserC(complexe);
	void affich();
};


main.cpp :
#include"complexe.h"
#include"string.h"
using namespace std;
void main()
{
	complexe c, c1;
	c.init_complexe(1,2);
	c1.init_complexe(2,2);
	c.AddionnerC(c1);
	c.affich();

}

// z1=5+3i
// z2=2-i
// z1*z2=(5*2)-5i+(3i*2)-(3i*i)
// z1+z2=(5+2)+(3-1)i


MERCI :)

P.S. Normalement le programme principal devrait réaliser l'addition de deux matrices nxn de nombres complexes, mais comme je ne savais pas comment le faire, je me suis contentée d'effectuer quelques méthodes simples.
0
void complexe::init_complexe(float reel, float imag)
{
reel=0;
imag=0;
}


tu utilise reel dans les variable de la foction et dans la classe je pense que ce que tu doit faire pour initialiser:

//complexe.cpp
void complexe::init_complexe(float init_ reel, float init_imag)
{
reel=init_reel;
imag=init_imag;
}

//complexe.h
void complexe::init_complexe(float init_ reel, float init_imag);



morale: change bien le nom de tes variables pour ne pas les confondre (moi pour les variable membre j'ecrit:m_maVariable)
0
mamiemando Messages postés 33076 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 17 avril 2024 7 748
17 déc. 2007 à 23:08
Hum ca va pas, il y a des confusions.

Une méthode s'applique à *this, qui est en fait un paramètre à part entière de la méthode. En particulier dans tes méthodes les complexes déclarés en variables locales devraient en fait être *this. Par ailleurs tu ne peux pas accéder aux champs reel et imag des complexes autres que *this car ces membres sont privés. Ou alors si this n'est pas exploité, c'est que ton opérateur ne devrait pas être dans la classe.

Les paramètres de ton constructeurs ne sont pas exploités pour initialiser ton objet.

Par convention on ne met jamais de majuscules aux noms de méthode. A la rigueur on en met uniquement pour les noms de classe et en pratique c'est plutôt réservé aux paramètres templates.

Je vire la méthode init qui devrait en fait intervenir au niveau du constructeur.

Afin de condenser le programme j'ai rassembler la déclaration de tes méthodes et leur implémentation mais ta manière de faire est tout à fait juste (et même mieux).

Voici une façon de faire si on repart de ce qui est déjà fait :
#include <iostream>

class complexe{
    private :
        float reel;
        float imag;
    public :
        complexe(float reel0 = 0, float imag0 = 0):
            reel(reel0),imag(imag0)
        {}

        inline const float & re() const{
            return reel;
        }

        inline const float & im() const{
            return imag;
        }

        inline complexe multiplier_r(const float & r){
            reel *= r; // reel équivaut à this->reel
            return *this;
        }

        inline complexe multiplier_c(const complexe & c){
            reel = re() * c.re() - im() * c.im();
            imag = re() * c.im() - im() * c.re();
            return *this;
        }

        inline complexe additionner_r(const float & r){
            reel += r;
            return *this;
        }

        inline complexe addionner_c(const complexe & c){
            reel = re() + c.re();
            imag = im() + c.im();
            return *this;
        }

        inline void affich() const {
            std::cout << " " << re() << " + " << im() << "i" << std::endl;
        };
};

inline complexe operator + (const complexe & c,const float & r){
    complexe res(c);
    res.additionner_r(r);
    return res;
}

inline complexe operator + (const float & r,const complexe & c){
    return c + r;
}

inline complexe operator + (const complexe & x,const complexe & y){
    complexe res(x);
    res.addionner_c(y);
    return res;
}

// idem pour *

int main(){
    complexe c(1,2), c1(2,2);
    c.addionner_c(c1);
    c.affich();
    return 0;
}

Voici comment on peut faire uniquement avec des opérateurs :
#include <iostream>
#include <ostream>

// La classe des imaginaires purs ------------------------------
// Cette classe encapsule un imaginaire pur par exemple z = 69i

class imaginaire{
    protected:
        float imag;
    public:
        imaginaire(const float & x):imag(x){}

        inline const float & im() const{
            return imag;
        }

        inline void set_im(const float & x){
            imag = x;
        }
};

// Grace à cet opérateur je peux directement écrire un imaginaire dans un flux,
// par exemple std::cout, std::cerr, ou n'importe quel std::ofstream (fichier
// ouvert en écriture)
inline std::ostream & operator << (std::ostream & out,const imaginaire & x){
    out << x.im() << 'i';
    return out;
}

// L'addition des imaginaires purs
inline imaginaire operator + (const imaginaire & x,const imaginaire & y){
    return imaginaire(x.im() + y.im());
}

// La multiplication des imaginaires purs
inline float operator * (const imaginaire & x,const imaginaire & y){
    return - (x.im() * y.im());
}

// Le produit d'un imaginaire par un réel
inline float operator * (const imaginaire & x,const float & y){
    return imaginaire(y * x.im());
}

// Pour le produit d'un réel et d'un imaginaire, je réutilise l'opérateur précédent
// Il s'agit bien d'un opérateur différent de :
// inline float operator * (const imaginaire & x,const float & y)
inline  float operator * (const float & x,const imaginaire & y){
    return y * x;
}

// La classe des complexes ------------------------------

// Comme je suis une grosse flemmarde je vais réutiliser par héritage la classe
// imaginaire que je viens de définir pour implémenter un complexe. Grosso modo
// un complexe c'est un imaginaire enrichi d'une partie réelle, donc l'héritage
// prend tout son sens. En particulier je pourrais directement utiliser les
// méthodes de la classe imaginaire sur un complexe (par exemple im())

class complexe : public imaginaire{
    private:
        float reel;
    public:

        complexe(float reel0 = 0,float imag0 = 0):
            imaginaire(imag0),
            reel(reel0)
        {}

        complexe(const imaginaire & x):
            imaginaire(x),
            reel(0)
        {}

        inline const float & re() const{
            return reel;
        }

        inline void set_re(const float & x){
            reel = x;
        }
};

// Ecriture : ici je réutilise :
// inline std::ostream & operator << (std::ostream & out,const imaginaire & x)
inline std::ostream & operator << (std::ostream & out,const complexe & x){
    out << x.re() << '+' << imaginaire(x.im());
    return out;
}

// Addition
// J'aurais pu réutiliser l'addition des imaginaires mais bon ici c'est quand même
// plus lisible comme ça...
complexe operator +(const complexe & x,const complexe & y){
    return complexe(
        x.re() + y.re(),
        x.im() + y.im()
    );
}

// Cette fonction template va permettre d'additionner
// un objet de type T  à un complexe. Il faut juste avoir un constructeur 
// convertissant un objet de type T en complexe pour que cette fonction 
// ait un sens (donc un imaginaire ou un float)
template <typename T>
complexe operator + (const complexe & x,const T & y){
    return x + complexe(y);
}

// Même chose pour additionner un objet de type T à gauche
template <typename T>
complexe operator + (const T & x,const complexe & y){
    return complexe(x) + y;
}

// Multiplication
inline complexe operator * (const complexe & x,const complexe & y){
    return complexe(
        (x.re() * y.re()) - (x.im() * y.im()),
        (x.re() * y.im()) + (x.im() * y.re())
    );
}

template <typename T>
complexe operator * (const complexe & x,const T & y){
    return x * complexe(y);
}

template <typename T>
complexe operator * (const T & x,const complexe & y){
    return complexe(x) * y;
}

// Le main ------------------------------

int main(){
    complexe x(1,2), y(2,2);
    std::cout << "x = " << x << std::endl
              << "y = " << y << std::endl
              << "x + y = " << x + y << std::endl;
    imaginaire z(7);
    std::cout << "z = " << z << std::endl
              << "x + z = " << x + z << std::endl;
    return 0;
}

Et à l'exécution :
x = 1+2i
y = 2+2i
x + y = 3+4i
z = 7i
x + z = 1+9i

En espérant que ça t'ai aidé, bon courage !
0
Utilisateur anonyme
26 déc. 2007 à 10:52
Resalut,

Merci de tes explications, je les ai bien notées et je ferai de mon mieux la prochaine fois.

Un petit cadeau pour toi :
https://www.cjoint.com/?mAkZH8Agb1

Bonne journée :)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Utilisateur anonyme
8 janv. 2008 à 19:51
Salut,

Je n’ai pas bien saisi ce post car à l’époque, on n’avait pas encore vu la surcharge des opérateurs, je reviens maintenant après avoir avalé la pilule des opérateurs chargés (je l’ai avalée mais pas encore digérée) :(

Je n’ai pas trop compris les deux lignes suivantes :

inline const float & re() const{
            return reel;
        }

        inline const float & im() const{
            return imag;
        }


On ne pourrait pas s’en passer et utiliser les paramètres reel et imag tout simplement ?

Sinon, j’ai une autre question, si l’imaginaire du résultat de l’addition de deux complexe est négatif, au moment de l’affichage, nous aurons quelque chose qui ressemble à ça par exemple : 3 + - 6i

Comment pourrais-je éviter de tel affichage ?

P.S. Je n’ai pu comprendre que la première partie, mais quand il s’agissait uniquement des opérateurs (tout ce qui existe dessous de cette phrase : Voici comment on peut faire uniquement avec des opérateurs … ) j’ai séché.. Avec plus de pratique, je finirai par m’y familiariser ;)

Merci infiniment :)
0
mamiemando Messages postés 33076 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 17 avril 2024 7 748
8 janv. 2008 à 21:17
Merci pour le cadeau c'est la classe ;-)

Je n’ai pas trop compris les deux lignes suivantes :

Là ce sont deux accesseurs "en lecture seule", qui retourne une const référence aux champs "reel" et "imag" d'un objet de type "complexe".
- Le mot clé inline précise que chaque appel à cette fonction doit être remplacé par le compilateur directement par le code de la fonction. Ceci a un sens si la méthode en question ne fait que quelques instructions ou est implémentée dans un header.
- le mot clé const signifie qu'une variable (paramètre, variable locale, valeur de retour) est maintenue constante
- const float & signifie que la fonction ne recopie pas le float stocké dans le complexe mais directement son adresse (d'où le concept de référence). Ainsi le float (beaucoup plus grand en mémoire qu'une adresse) ne sera recopié qu'en cas de nécessité (en gros si tu as besoin de manipuler autre chose qu'un "const float".
- Le const en fin de prototype signale que *this ne sera pas modifié par la méthode (im() ou re()), ce qui est en effet le cas puiqu'on retourne une référence.

On ne pourrait pas s’en passer et utiliser les paramètres reel et imag tout simplement ?

Ah non car ce sont les deux champs qui stockent les flottants encapsulés par un complexe. Il faut bien les stocker quelque part !! Par contre on pourrait imaginer que ces deux flottants soient directement accessible (en public) et ainsi se passer d'accesseurs (ici re(), set_re(), im(), et set_im()). L'avantage des accesseurs c'est que tu contrôles l'accès aux champs d'un objet, et tu garantis ainsi que ton objet n'est pas utilisé à mauvais escient.

En d'autre termes, on ne peut pas changer les champs de ton objet "dans ton dos". C'est particulièrement important si ces valeurs sont susceptibles de provoquer un comportement non désiré. Par exemple suppose que tu veuilles implémenter un vecteur d'entier, encapsulant un int * (le tableau des valeurs stockées dans le vecteur) et un unsigned (le nombre de valeur). Un utilisateur ne doit pas accéder à une case hors de ce vecteur (sinon ça fait une erreur de segmentation). Ainsi un accesseur peut contrôler que c'est bien toujours le cas. Cependant il ne faut pas que le champ "taille" puisse être changé à ton insu avec une taille invalide (sinon le contrôle sur la taille sera caduque !). Ce petit exemple illustre à mon avis bien l'intérêt des accesseurs.

Sinon, j’ai une autre question, si l’imaginaire du résultat de l’addition de deux complexe est négatif, au moment de l’affichage, nous aurons quelque chose qui ressemble à ça par exemple : 3 + - 6i

Il suffit de patcher ton opérateur << pour les complexes :
inline std::ostream & operator << (std::ostream & out,const complexe & x){
    out << x.re();
    const float x_im = x.im();
    if(x.im() < 0) out << '+';
    else out << '-';
    out << imaginaire(std::abs(x_im));
    return out;
}

Si std::abs ne marche pas tu peux l'implémenter toi même
template <typename T>
T abs(const T & x){
  return (x < 0 ? -x : x);
}

P.S. Je n’ai pu comprendre que la première partie, mais quand il s’agissait uniquement des opérateurs (tout ce qui existe dessous de cette phrase : Voici comment on peut faire uniquement avec des opérateurs … ) j’ai séché.. Avec plus de pratique, je finirai par m’y familiariser ;)


Ben ici on utilise uniquement des opérateurs (+, << etc...) au lieu de MultiplierR(float) etc qui sont des méthodes.

Bonne chance
0
Utilisateur anonyme
8 janv. 2008 à 21:54
Un GRAND MERCI à toi !

Demain, c'est un jour férié chez nous et je ne ferai qu'étudier le C++....

(J'ai eu 13 dans mon devoir surveillé, il faut que je travaille plus hardiment pour que je réussisse l'examen), je ne suis pas satisfaiteuuuh, sniiif !

Entre nous, c'est difficile la surcharge des opérateurs :'(

Bonne soirée :)
0
mamiemando Messages postés 33076 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 17 avril 2024 7 748
8 janv. 2008 à 22:52
Tinquiète ça viendra. SI tu rencontres d'autres difficultés en C++ n'hésite pas à ouvrir un nouveau post sur le forum programmation.

Bonne chance et bonne continuation
0