mikrocontroller.net

Forum: PC-Programmierung friend-Problem


Autor: der_lebende (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Ich mache zur Zeit ein Fernstudium, habe eine Aufgabe, dessen Quelltext 
Fehler beinhaltet.

Ich schicke euch hiermit mal den Quelltext, weitestgehend von mir 
abgeändert, wo ich Fehler gefunden habe.
Diese sind mit einem Kommentar beschrieben.


Hier der Code:
/**************************************************************************/
/* e1x_12           Fehlerhaftes Programm zur Einsendeaufgabe 1           */
/**************************************************************************/
#include <stdio.h>

#define BIL printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")

class Frau;                                    // Vorwaertsdeklaration noetig

/*------------------------------------------------------------------------*/

class Haendler
{
private:
  

public:
  float preis[4];
  void setze_preis(int i, float p)     {preis[i]=p;};
  void zeige_preise()
  {
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
     preis[0],preis[1],preis[2],preis[3]);
  }
  //float gib_preis(int i)               { return preis[i];};
   friend float rechne_gesamt(Haendler &h, Frau &f);                               //friend abgeändert von frend
};
/*------------------------------------------------------------------------*/

class Frau
{
private:
  

public:
  float menge[4];                                  //!! Muss public sein
  void setze_menge(int i, float m)     {menge[i]=m;};
  void zeige_mengen()
  {
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
     menge[0],menge[1],menge[2],menge[3]);
  }
  //float gib_menge(int i)               { return menge[i];};
    float rechne_gesamt(Haendler &h, Frau &f);
};
/**************************************************************************/
int main (void)
{
  Frau mueller, meier;
  Haendler haendler1, haendler2;

  float ergebnis1=0.0,
        ergebnis2=0.0,
        ergebnis3=0.0,
        ergebnis4=0.0;

  haendler1.setze_preis(0, 0.20);                      // Preise je Produkt
  haendler1.setze_preis(1, 0.28);
  haendler1.setze_preis(2, 0.88);
  haendler1.setze_preis(3, 1.30);

  haendler2.setze_preis(0, 0.18);
  haendler2.setze_preis(1, 0.29);
  haendler2.setze_preis(2, 0.84);
  haendler2.setze_preis(3, 1.58);

  mueller.setze_menge(0,6);                             // Mengen je Produkt
  mueller.setze_menge(1,6);
  mueller.setze_menge(2,0.25);
  mueller.setze_menge(3,3);

  meier.setze_menge(0,10);
  meier.setze_menge(1,3);
  meier.setze_menge(2,0.5);
  meier.setze_menge(3,1);

/**************************************************************************/

/**************************************************************************/
/*      Berechnen der Ergebnisse und Speichern im Array ergebnis[][]      */
/**************************************************************************/

  ergebnis1 = rechne_gesamt(haendler1, mueller);
  ergebnis2 = rechne_gesamt(haendler2, mueller);
  ergebnis3 = rechne_gesamt(haendler1, meier);
  ergebnis4 = rechne_gesamt(haendler2, meier);

/**************************************************************************/
/*                        Ausgabe der Werte der Arrays                    */
/**************************************************************************/

  BIL;
  printf("\n\tPreise bei den beiden Haendlern:");
  printf("\n\n\tI Preise      Broetchen I  Eier   I Butter  I  Kaese  I");
  printf("\n\tI Haendler1 :"); haendler1.zeige_preise();
  printf("\n\tI Haendler2 :"); haendler2.zeige_preise();

  printf("\n\n\n\tEinkaufslisten der beiden Frauen:");
  printf("\n\n\tI Mengen      Broetchen I  Eier   I Butter  I  Kaese  I");
  printf("\n\tI Mueller   :"); mueller.zeige_mengen();
  printf("\n\tI Meier     :"); meier.zeige_mengen();

  printf("\n\n\n\tGesamtkosten der Einkaufslisten:");
  printf("\n\n\tI Ges.Preis     Mueller I  Meier  I");
  printf("\n\tI Haendler 1:  %7.2f  I%7.2f  I",
       ergebnis1,ergebnis3);
  printf(  "\n\tI Haendler 2:  %7.2f  I%7.2f  I",
       ergebnis2,ergebnis4);

  printf("\n\n\t Bitte druecken Sie eine beliebige Taste");
  printf("\n\t");

  printf("\n\n");                                          // Programm anhalten
}
/**************************************************************************/
float rechne_gesamt(Haendler h, Frau f)
{
  int i;
  float gesamt=0.0;

  for (i=0; i<4; i++)
     gesamt += h.preis[i] * f.menge[i];

  return gesamt;
}
/**************************************************************************/







Allerdings lässt sich der Quelltext nicht übersetzen, da mein VS2008 als 
Fehler ausgibt, dass ein
"Verweis auf nicht aufgelöstes externes Symbol ""float__cdecl rechne_gesamt(........)" 
besteht.

Woran liegt das?

Stehe gerade wirklich auf dem Schlauch.


Vielen Dank!

Autor: Alfred (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das könnte daran liegen, dass rechne_gesamt() erst nach main(), in der 
Du sie benutzt deklariert wird. Also vor main() einen Prototypen 
platzieren:

float rechne_gesamt(Haendler h, Frau f);

Du könntest auch die ganze rechne_gesamt() vor main() platzieren, ich 
würde aber die Version mit dem Prototypen bevorzugen.

Viele Grüße

Alfred

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du deklarierst in beiden Klassen eine Funktion rechne_gesamt, aber 
implementierst keine davon.

Das ist aber gar nicht erforderlich, ebensowenig das friend und auch 
nicht die Vorwärtsdeklaration.

Das einzige, das Dir fehlt, ist der klassenlose Prototyp von 
"rechne_gesamt", wie Alfred schon riet.

Damit ergibt sich folgendes:

class Haendler
{
public:
  float preis[4];
  void setze_preis(int i, float p)     {preis[i]=p;};
  void zeige_preise()
  {
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
     preis[0],preis[1],preis[2],preis[3]);
  }
  //float gib_preis(int i)               { return preis[i];};
};


class Frau
{

public:
  float menge[4];                                  //!! Muss public sein
  void setze_menge(int i, float m)     {menge[i]=m;};
  void zeige_mengen()
  {
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
     menge[0],menge[1],menge[2],menge[3]);
  }
  //float gib_menge(int i)               { return menge[i];};
};



// Funktionsprototyp 
float rechne_gesamt(Haendler h, Frau f);


int main (void)
{
  // etc.
}


float rechne_gesamt(Haendler h, Frau f)
{
  // etc.
}


Das ist natürlich aus der Sicht der Objektorientierung ziemlicher 
Schrunz, in rechne_gesamt greifst Du direkt auf Member der beiden 
Klassen zu, was ein no-go sein sollte. Auch ist das Wissen, daß die 
Member-Arrays beider Klassen ausgerechnet vier Elemente enthalten, hier 
fest codiert.

Autor: Lehrer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du bei der Aufgbabe auch etwas lernen möchtest, solltest Du 
vielleicht mal unter dem Stichwort "Datenkapselung" nachlesen.
Einige Deiner Änderungen erscheinen sind unter diesem Gesichtspunkt 
nicht sinnvoll, dafür fehlt eine entscheidende Änderung in 
"rechne_gesamt".
Einen Blick wert wären auch die Formatspezifizierungen bei "printf".
Soweit mal auf die Schnelle...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die globale Funktion rechne_gesamt() ist ziemlich krank, aber 
wahrscheinlich so vorgegeben.

Zumindest würde ich es so schreiben:
float rechne_gesamt( const Haendler &h, const Frau &f )
{
  ...

Damit es wenigstens übersetzbar ist, muß zudem erstens in beiden Klassen 
die Funktion als friend deklarieert werden (ist beim OP nur in 
Haendler).
Also mit meinem Vorschlag von oben in beiden Klassen so:
   friend float rechne_gesamt( const Haendler &h, const Frau &f );

Dazu kommt, daß der Compiler in Haendler noch nichts von Frau weiß.
Also muß davor in Haendler noch stehen:
  class Frau;
  friend float rechne_gesamt( const Haendler &h, const Frau &f );
  ...

Zu meckern gibt es noch mehr, aber das ist mir erst mal als echte Hürde 
aufgefallen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Das ist aber gar nicht erforderlich, ebensowenig das friend und auch
> nicht die Vorwärtsdeklaration.

Solange alles public ist, ist das friend tatsächlich überflüssig.
Aber besser wäre es, die Daten der Klassen private oder protected zu 
machen, dann ist das friend wieder nötig.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der_lebende schrieb:

> Ich mache zur Zeit ein Fernstudium, habe eine Aufgabe, dessen Quelltext
> Fehler beinhaltet.

Musst du nur syntaktische Fehler finden, oder auch Design und 
Logikfehler?

(die Funktion rechen_gesamt rechnet falsch. Sie berücksichtigt nicht, 
dass die Kunden die Produkte nicht in derselben Reihenfolge einkaufen, 
in der sie die Händler führen)

Autor: der_lebende (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe es jetzt so abgeändert, es bestehen trotzdem weiterhin 2 Fehler, 
einmal der Vorherige (externes Symbol ...) und "fatal error LNK1120: 1 
nicht aufgelöste externe Verweise".


Hier der bis dato abgeänderte Code:

/**************************************************************************/
/* e1x_12           Fehlerhaftes Programm zur Einsendeaufgabe 1           */
/**************************************************************************/
#include <stdio.h>

#define BIL printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")

class Frau;                                    // Vorwaertsdeklaration noetig

/*------------------------------------------------------------------------*/


class Haendler
{
private:
  

public:
  float preis[4];
  void setze_preis(int i, float p)     {preis[i]=p;};
  void zeige_preise()
  {
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
     preis[0],preis[1],preis[2],preis[3]);
  }
  //float gib_preis(int i)               { return preis[i];};
  class Frau;  
  friend float rechne_gesamt(Haendler &h, Frau &f);                               //friend abgeändert von frend
};
/*------------------------------------------------------------------------*/

class Frau
{
private:
  

public:
  float menge[4];                                  //!! Muss public sein
  void setze_menge(int i, float m)     {menge[i]=m;};
  void zeige_mengen()
  {
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
     menge[0],menge[1],menge[2],menge[3]);
  }
  //float gib_menge(int i)               { return menge[i];};
    friend float rechne_gesamt(Haendler &h, Frau &f);
};
/**************************************************************************/

float rechne_gesamt(Haendler &h, Frau &f);

int main (void)
{
  Frau mueller, meier;
  Haendler haendler1, haendler2;

  float ergebnis1=0.0,
        ergebnis2=0.0,
        ergebnis3=0.0,
        ergebnis4=0.0;

  haendler1.setze_preis(0, 0.20);                      // Preise je Produkt
  haendler1.setze_preis(1, 0.28);
  haendler1.setze_preis(2, 0.88);
  haendler1.setze_preis(3, 1.30);

  haendler2.setze_preis(0, 0.18);
  haendler2.setze_preis(1, 0.29);
  haendler2.setze_preis(2, 0.84);
  haendler2.setze_preis(3, 1.58);

  mueller.setze_menge(0,6);                             // Mengen je Produkt
  mueller.setze_menge(1,6);
  mueller.setze_menge(2,0.25);
  mueller.setze_menge(3,3);

  meier.setze_menge(0,10);
  meier.setze_menge(1,3);
  meier.setze_menge(2,0.5);
  meier.setze_menge(3,1);

/**************************************************************************/

/**************************************************************************/
/*      Berechnen der Ergebnisse und Speichern im Array ergebnis[][]      */
/**************************************************************************/

  ergebnis1 = rechne_gesamt(haendler1, mueller);
  ergebnis2 = rechne_gesamt(haendler2, mueller);
  ergebnis3 = rechne_gesamt(haendler1, meier);
  ergebnis4 = rechne_gesamt(haendler2, meier);

/**************************************************************************/
/*                        Ausgabe der Werte der Arrays                    */
/**************************************************************************/

  BIL;
  printf("\n\tPreise bei den beiden Haendlern:");
  printf("\n\n\tI Preise      Broetchen I  Eier   I Butter  I  Kaese  I");
  printf("\n\tI Haendler1 :"); haendler1.zeige_preise();
  printf("\n\tI Haendler2 :"); haendler2.zeige_preise();

  printf("\n\n\n\tEinkaufslisten der beiden Frauen:");
  printf("\n\n\tI Mengen      Broetchen I  Eier   I Butter  I  Kaese  I");
  printf("\n\tI Mueller   :"); mueller.zeige_mengen();
  printf("\n\tI Meier     :"); meier.zeige_mengen();

  printf("\n\n\n\tGesamtkosten der Einkaufslisten:");
  printf("\n\n\tI Ges.Preis     Mueller I  Meier  I");
  printf("\n\tI Haendler 1:  %7.2f  I%7.2f  I",
       ergebnis1,ergebnis3);
  printf(  "\n\tI Haendler 2:  %7.2f  I%7.2f  I",
       ergebnis2,ergebnis4);

  printf("\n\n\t Bitte druecken Sie eine beliebige Taste");
  printf("\n\t");

  printf("\n\n");                                          // Programm anhalten
}
/**************************************************************************/
float rechne_gesamt(Haendler h, Frau f)
{
  int i;
  float gesamt=0.0;

  for (i=0; i<4; i++)
     gesamt += h.preis[i] * f.menge[i];

  return gesamt;
}
/**************************************************************************/





Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Rufus t. Firefly schrieb:
>> Das ist aber gar nicht erforderlich, ebensowenig das friend und auch
>> nicht die Vorwärtsdeklaration.
>
> Solange alles public ist, ist das friend tatsächlich überflüssig.
> Aber besser wäre es, die Daten der Klassen private oder protected zu
> machen, dann ist das friend wieder nötig.

Kann man streiten.
Grundsätzlich sollte ja niemand von ausserhalb einer Klasse direkt auf 
die Member einer Klasse zugreifen, sondern immer über Zugriffsfunktionen 
gehen.

Dann ist das friend wieder nicht nötig.


friend sollte man, wenn überhaupt, nur dann benutzen, wenn zwei Klassen 
in wirklich enger und inniger Beziehung zueinander stehen. Ob das bei 
einem Händler und seinen Kunden der Fall ist, darf bezweifelt werden.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der_lebende schrieb:
> Habe es jetzt so abgeändert, es bestehen trotzdem weiterhin 2 Fehler,
> einmal der Vorherige (externes Symbol ...) und "fatal error LNK1120: 1
> nicht aufgelöste externe Verweise".

Du vereinbarst hier


>   friend float rechne_gesamt(Haendler &h, Frau &f);

und hier

>     friend float rechne_gesamt(Haendler &h, Frau &f);

das es eine Funktion rechne_gesamt gibt.

Für diese Funktion hast du sogar einen Prototypen

> float rechne_gesamt(Haendler &h, Frau &f);


Aber du hast die Funktion selber nicht!

Das hier ist sie nicht. Vergleich mal die Argumenttypen

> /*********************************************************************** ***/
> float rechne_gesamt(Haendler h, Frau f)
> {
>   int i;
>   float gesamt=0.0;
>
>   for (i=0; i<4; i++)
>      gesamt += h.preis[i] * f.menge[i];
>
>   return gesamt;
> }
> /*********************************************************************** ***/

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:

> (die Funktion rechen_gesamt rechnet falsch. Sie berücksichtigt nicht,
> dass die Kunden die Produkte nicht in derselben Reihenfolge einkaufen,
> in der sie die Händler führen)

Zieh ich zurück.
Das wird tatsächlich dadurch gelöst, wie Frauen ihren Einkauf speichern.
Schön ist es nicht - es verallgemeinert schlecht. Wenn Händler 
unterschiedliche Produkte anbieten von denen die Frau nur einige und 
nicht alle kauft, bricht alles zusammen.
Aber im konkreten Fall kommt das richtige heraus.

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gah. Immer dieses Gemixe von C und C++ :-(

Dabei ist die Bildschirmausgabe mit cout doch nun sooo schwer auch 
wieder nicht:

http://www.java2s.com/Tutorial/Cpp/0100__Developme...

Autor: Simon Budig (nomis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark Brandis schrieb:
> Gah. Immer dieses Gemixe von C und C++ :-(
>
> Dabei ist die Bildschirmausgabe mit cout doch nun sooo schwer auch
> wieder nicht:

Genau.
std::cout << std::hex << std::setfill('0') << std::setw(8) << x << std::dec << std::endl; 
ist ja auch deutlich einfacher als
printf("0x%08x\n", x);

:-)

Viele Grüße,
        Simon

PS: (nein, ist nicht mein Beispiel, das stammt von 
http://yosefk.com/c++fqa/io.html#fqa-15.1 )

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Grundsätzlich sollte ja niemand von ausserhalb einer Klasse direkt auf
> die Member einer Klasse zugreifen, sondern immer über Zugriffsfunktionen
> gehen.
>
> Dann ist das friend wieder nicht nötig.

Da gebe ich dir vollkommen recht.
Nur scheint es mir hier vorgegeben, und ich weiß nicht,
wie weit man daraus jetzt ein sinnvolles Programm machen soll.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Zieh ich zurück.
> Das wird tatsächlich dadurch gelöst, wie Frauen ihren Einkauf speichern.

Männer werden nie verstehen, wie das mit Frauen und Einkauf 
funktioniert.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Für diese Funktion hast du sogar einen Prototypen
>
>> float rechne_gesamt(Haendler &h, Frau &f);

Zudem:
Kein echter Fehler, aber eine Schlamperei sind bei den
Referenzen die fehlenden const (siehe oben).

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Budig schrieb:
> Genau.
>
>
> std::cout << std::hex << std::setfill('0') << std::setw(8) << x <<
> std::dec << std::endl;
> 
> ist ja auch deutlich einfacher

Kein normaler Mensch schreibt hunderttausendmal pro Datei std::cout, 
std::endl usw. - dafür gibt's ja using std::cout etc. :-)

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hältst Du denn

> cout << hex << setfill('0') << setw(8) << x << dec << endl;

ernsthaft für übersichtlich?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark Brandis schrieb:
> Kein normaler Mensch schreibt hunderttausendmal pro Datei std::cout,
> std::endl usw. - dafür gibt's ja using std::cout etc. :-)

Vielleicht bin ich ja nicht normal, aber ich schreibe das aus.
Bzw. lasse es vom Editor ausschreiben.

using nehme ich so gut wie nie.
Genau genommen gar nicht.

Autor: der_lebende (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok vielen Dank für eure Hilfe!

Es hat wunderbar geklappt :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.