Forum: PC-Programmierung friend-Problem


von der_lebende (Gast)


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:
1
/**************************************************************************/
2
/* e1x_12           Fehlerhaftes Programm zur Einsendeaufgabe 1           */
3
/**************************************************************************/
4
#include <stdio.h>
5
6
#define BIL printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
7
8
class Frau;                                    // Vorwaertsdeklaration noetig
9
10
/*------------------------------------------------------------------------*/
11
12
class Haendler
13
{
14
private:
15
  
16
17
public:
18
  float preis[4];
19
  void setze_preis(int i, float p)     {preis[i]=p;};
20
  void zeige_preise()
21
  {
22
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
23
     preis[0],preis[1],preis[2],preis[3]);
24
  }
25
  //float gib_preis(int i)               { return preis[i];};
26
   friend float rechne_gesamt(Haendler &h, Frau &f);                               //friend abgeändert von frend
27
};
28
/*------------------------------------------------------------------------*/
29
30
class Frau
31
{
32
private:
33
  
34
35
public:
36
  float menge[4];                                  //!! Muss public sein
37
  void setze_menge(int i, float m)     {menge[i]=m;};
38
  void zeige_mengen()
39
  {
40
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
41
     menge[0],menge[1],menge[2],menge[3]);
42
  }
43
  //float gib_menge(int i)               { return menge[i];};
44
    float rechne_gesamt(Haendler &h, Frau &f);
45
};
46
/**************************************************************************/
47
int main (void)
48
{
49
  Frau mueller, meier;
50
  Haendler haendler1, haendler2;
51
52
  float ergebnis1=0.0,
53
        ergebnis2=0.0,
54
        ergebnis3=0.0,
55
        ergebnis4=0.0;
56
57
  haendler1.setze_preis(0, 0.20);                      // Preise je Produkt
58
  haendler1.setze_preis(1, 0.28);
59
  haendler1.setze_preis(2, 0.88);
60
  haendler1.setze_preis(3, 1.30);
61
62
  haendler2.setze_preis(0, 0.18);
63
  haendler2.setze_preis(1, 0.29);
64
  haendler2.setze_preis(2, 0.84);
65
  haendler2.setze_preis(3, 1.58);
66
67
  mueller.setze_menge(0,6);                             // Mengen je Produkt
68
  mueller.setze_menge(1,6);
69
  mueller.setze_menge(2,0.25);
70
  mueller.setze_menge(3,3);
71
72
  meier.setze_menge(0,10);
73
  meier.setze_menge(1,3);
74
  meier.setze_menge(2,0.5);
75
  meier.setze_menge(3,1);
76
77
/**************************************************************************/
78
79
/**************************************************************************/
80
/*      Berechnen der Ergebnisse und Speichern im Array ergebnis[][]      */
81
/**************************************************************************/
82
83
  ergebnis1 = rechne_gesamt(haendler1, mueller);
84
  ergebnis2 = rechne_gesamt(haendler2, mueller);
85
  ergebnis3 = rechne_gesamt(haendler1, meier);
86
  ergebnis4 = rechne_gesamt(haendler2, meier);
87
88
/**************************************************************************/
89
/*                        Ausgabe der Werte der Arrays                    */
90
/**************************************************************************/
91
92
  BIL;
93
  printf("\n\tPreise bei den beiden Haendlern:");
94
  printf("\n\n\tI Preise      Broetchen I  Eier   I Butter  I  Kaese  I");
95
  printf("\n\tI Haendler1 :"); haendler1.zeige_preise();
96
  printf("\n\tI Haendler2 :"); haendler2.zeige_preise();
97
98
  printf("\n\n\n\tEinkaufslisten der beiden Frauen:");
99
  printf("\n\n\tI Mengen      Broetchen I  Eier   I Butter  I  Kaese  I");
100
  printf("\n\tI Mueller   :"); mueller.zeige_mengen();
101
  printf("\n\tI Meier     :"); meier.zeige_mengen();
102
103
  printf("\n\n\n\tGesamtkosten der Einkaufslisten:");
104
  printf("\n\n\tI Ges.Preis     Mueller I  Meier  I");
105
  printf("\n\tI Haendler 1:  %7.2f  I%7.2f  I",
106
       ergebnis1,ergebnis3);
107
  printf(  "\n\tI Haendler 2:  %7.2f  I%7.2f  I",
108
       ergebnis2,ergebnis4);
109
110
  printf("\n\n\t Bitte druecken Sie eine beliebige Taste");
111
  printf("\n\t");
112
113
  printf("\n\n");                                          // Programm anhalten
114
}
115
/**************************************************************************/
116
float rechne_gesamt(Haendler h, Frau f)
117
{
118
  int i;
119
  float gesamt=0.0;
120
121
  for (i=0; i<4; i++)
122
     gesamt += h.preis[i] * f.menge[i];
123
124
  return gesamt;
125
}
126
/**************************************************************************/



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

Woran liegt das?

Stehe gerade wirklich auf dem Schlauch.


Vielen Dank!

von Alfred (Gast)


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

von Rufus Τ. F. (rufus) Benutzerseite


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:
1
class Haendler
2
{
3
public:
4
  float preis[4];
5
  void setze_preis(int i, float p)     {preis[i]=p;};
6
  void zeige_preise()
7
  {
8
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
9
     preis[0],preis[1],preis[2],preis[3]);
10
  }
11
  //float gib_preis(int i)               { return preis[i];};
12
};
13
14
15
class Frau
16
{
17
18
public:
19
  float menge[4];                                  //!! Muss public sein
20
  void setze_menge(int i, float m)     {menge[i]=m;};
21
  void zeige_mengen()
22
  {
23
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
24
     menge[0],menge[1],menge[2],menge[3]);
25
  }
26
  //float gib_menge(int i)               { return menge[i];};
27
};
28
29
30
31
// Funktionsprototyp 
32
float rechne_gesamt(Haendler h, Frau f);
33
34
35
int main (void)
36
{
37
  // etc.
38
}
39
40
41
float rechne_gesamt(Haendler h, Frau f)
42
{
43
  // etc.
44
}

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.

von Lehrer (Gast)


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...

von Klaus W. (mfgkw)


Lesenswert?

Die globale Funktion rechne_gesamt() ist ziemlich krank, aber 
wahrscheinlich so vorgegeben.

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

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:
1
   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:
1
  class Frau;
2
  friend float rechne_gesamt( const Haendler &h, const Frau &f );
3
  ...

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

von Klaus W. (mfgkw)


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.

von Karl H. (kbuchegg)


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)

von der_lebende (Gast)


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:
1
/**************************************************************************/
2
/* e1x_12           Fehlerhaftes Programm zur Einsendeaufgabe 1           */
3
/**************************************************************************/
4
#include <stdio.h>
5
6
#define BIL printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
7
8
class Frau;                                    // Vorwaertsdeklaration noetig
9
10
/*------------------------------------------------------------------------*/
11
12
13
class Haendler
14
{
15
private:
16
  
17
18
public:
19
  float preis[4];
20
  void setze_preis(int i, float p)     {preis[i]=p;};
21
  void zeige_preise()
22
  {
23
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
24
     preis[0],preis[1],preis[2],preis[3]);
25
  }
26
  //float gib_preis(int i)               { return preis[i];};
27
  class Frau;  
28
  friend float rechne_gesamt(Haendler &h, Frau &f);                               //friend abgeändert von frend
29
};
30
/*------------------------------------------------------------------------*/
31
32
class Frau
33
{
34
private:
35
  
36
37
public:
38
  float menge[4];                                  //!! Muss public sein
39
  void setze_menge(int i, float m)     {menge[i]=m;};
40
  void zeige_mengen()
41
  {
42
   printf("  %7.2f  I%7.2f  I%7.2f  I%7.2f  I",
43
     menge[0],menge[1],menge[2],menge[3]);
44
  }
45
  //float gib_menge(int i)               { return menge[i];};
46
    friend float rechne_gesamt(Haendler &h, Frau &f);
47
};
48
/**************************************************************************/
49
50
float rechne_gesamt(Haendler &h, Frau &f);
51
52
int main (void)
53
{
54
  Frau mueller, meier;
55
  Haendler haendler1, haendler2;
56
57
  float ergebnis1=0.0,
58
        ergebnis2=0.0,
59
        ergebnis3=0.0,
60
        ergebnis4=0.0;
61
62
  haendler1.setze_preis(0, 0.20);                      // Preise je Produkt
63
  haendler1.setze_preis(1, 0.28);
64
  haendler1.setze_preis(2, 0.88);
65
  haendler1.setze_preis(3, 1.30);
66
67
  haendler2.setze_preis(0, 0.18);
68
  haendler2.setze_preis(1, 0.29);
69
  haendler2.setze_preis(2, 0.84);
70
  haendler2.setze_preis(3, 1.58);
71
72
  mueller.setze_menge(0,6);                             // Mengen je Produkt
73
  mueller.setze_menge(1,6);
74
  mueller.setze_menge(2,0.25);
75
  mueller.setze_menge(3,3);
76
77
  meier.setze_menge(0,10);
78
  meier.setze_menge(1,3);
79
  meier.setze_menge(2,0.5);
80
  meier.setze_menge(3,1);
81
82
/**************************************************************************/
83
84
/**************************************************************************/
85
/*      Berechnen der Ergebnisse und Speichern im Array ergebnis[][]      */
86
/**************************************************************************/
87
88
  ergebnis1 = rechne_gesamt(haendler1, mueller);
89
  ergebnis2 = rechne_gesamt(haendler2, mueller);
90
  ergebnis3 = rechne_gesamt(haendler1, meier);
91
  ergebnis4 = rechne_gesamt(haendler2, meier);
92
93
/**************************************************************************/
94
/*                        Ausgabe der Werte der Arrays                    */
95
/**************************************************************************/
96
97
  BIL;
98
  printf("\n\tPreise bei den beiden Haendlern:");
99
  printf("\n\n\tI Preise      Broetchen I  Eier   I Butter  I  Kaese  I");
100
  printf("\n\tI Haendler1 :"); haendler1.zeige_preise();
101
  printf("\n\tI Haendler2 :"); haendler2.zeige_preise();
102
103
  printf("\n\n\n\tEinkaufslisten der beiden Frauen:");
104
  printf("\n\n\tI Mengen      Broetchen I  Eier   I Butter  I  Kaese  I");
105
  printf("\n\tI Mueller   :"); mueller.zeige_mengen();
106
  printf("\n\tI Meier     :"); meier.zeige_mengen();
107
108
  printf("\n\n\n\tGesamtkosten der Einkaufslisten:");
109
  printf("\n\n\tI Ges.Preis     Mueller I  Meier  I");
110
  printf("\n\tI Haendler 1:  %7.2f  I%7.2f  I",
111
       ergebnis1,ergebnis3);
112
  printf(  "\n\tI Haendler 2:  %7.2f  I%7.2f  I",
113
       ergebnis2,ergebnis4);
114
115
  printf("\n\n\t Bitte druecken Sie eine beliebige Taste");
116
  printf("\n\t");
117
118
  printf("\n\n");                                          // Programm anhalten
119
}
120
/**************************************************************************/
121
float rechne_gesamt(Haendler h, Frau f)
122
{
123
  int i;
124
  float gesamt=0.0;
125
126
  for (i=0; i<4; i++)
127
     gesamt += h.preis[i] * f.menge[i];
128
129
  return gesamt;
130
}
131
/**************************************************************************/

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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;
> }
> /*********************************************************************** ***/

von Karl H. (kbuchegg)


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.

von Mark B. (markbrandis)


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__Development/Controllingprecisionoffloatingpointvalues.htm

von Simon B. (nomis)


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.
1
std::cout << std::hex << std::setfill('0') << std::setw(8) << x << std::dec << std::endl;
ist ja auch deutlich einfacher als
1
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 )

von Klaus W. (mfgkw)


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.

von Klaus W. (mfgkw)


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.

von Klaus W. (mfgkw)


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).

von Mark B. (markbrandis)


Lesenswert?

Simon Budig schrieb:
> Genau.
>
>
1
> std::cout << std::hex << std::setfill('0') << std::setw(8) << x <<
2
> std::dec << std::endl;
3
>
> 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. :-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hältst Du denn

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

ernsthaft für übersichtlich?

von Klaus W. (mfgkw)


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.

von der_lebende (Gast)


Lesenswert?

Ok vielen Dank für eure Hilfe!

Es hat wunderbar geklappt :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.