Frage zu Klassenprogrammierungsaufgabe

drpingoo

Erfahrenes Mitglied
Hi zusammen,

ich hätte da ne Frage bezgl Klassenprogrammierung. Wahrscheinlich ist der Haken, den ich suche, ganz einfach, aber ich seh ihn wohl nicht. Und zwar gibt mir der Compeiler einen Fehler bei folgendem an:...Rechteck RE(A,B);... (siehe unten Code). Er sagt, dass ich keinen Zugriff habe auf private Member, dessen Deklaration in der Rechteck-Klasse erfolgte. Ich seh jetzt nicht, was da bei mir falsch ist, denn ich setze den Wert der Punkte über die Set-Fkt.

Danke schon mal für eure Hilfe.

Code:
#include <iostream>
#include <cmath>
using namespace std;

class Punkt {
private:
double x, y;

public:
Punkt(double X=0, double Y=0) { x=X; y=Y; } //Konstruktor
void set (double X , double Y) { x=X; y=Y; } //Methode
double getX () { return x; } // -"-
double getY () { return y; } // -"-
};

class Rechteck {

private:
Punkt P1,P2; 
Rechteck(Punkt punkt1, Punkt punkt2) {P1=punkt1, P2=punkt2;};

public:
	double Fläche(){
	double x1=P1.getX();
	double y1= P1.getY();
	double x2 =P2.getX();
	double y2 =P2.getY();
	double x_länge = abs(x2-x1);
	double y_länge = abs(y2-y1);

	return x_länge*y_länge;};


//double Umfang(umfang);


};

void main() {
// Zwei Variablen vom Typ "Punkt" zur Eingabe der Rechteckkoordinanten
Punkt A, B;
// Eingabe der Koordinaten der Punkte A und B
double x,y;
cout << "Koordinaten x und y Punkt A : "; cin >> x >> y; 
A.set(x,y);
cout << "Koordinaten x und y Punkt B : "; cin >> x >> y; 
B.set(x,y);

// Erzeugen eines Objekts der Klasse "Rechteck" und
// Berechnung des Umfangs und der Flaeche des Rechteckes
Rechteck RE(A,B);
cout << "Die Rechteckflaeche betraegt " << RE.Fläche() << endl;
//double Umfang;
//RE.Umfang(Umfang);
//cout << "Der Umfang des Rechteckes betraegt " << Umfang << endl;

}
 
Aber deine Rechteckt-Klasse hat doch nur einen privaten Konstruktor, das heißt doch, du kannst davon keine neuen Instanzen erstellen, oder?
 
Ehm ich schreib es dir mal "korrekter" ... aber dein Problem ist einfach, das der c-tor von Rechteck "private" ist ;)

C++:
class Point 
{
    std::pair<double, double> m_position;

public:
    Point(const double x = 0.0, const double y = 0,0) 
        : m_position(std::make_pair(x, y))
    {}

public:
    void set(const double x, const double y) { m_position.first = x; m_position.second = y; } 
    const double get_x() const { return m_position.first; } 
    const double get_y() const { return m_position.second; }
};


#include <cmath>

class Rect 
{
    Point m_lefttop;
    Point m_bottomright;

public:
    Rect(Point const& lefttop, Point const& bottomright)
        : m_lefttop(lefttop), m_bottomrigt(bottomright)
    {}

public:
    const double width() const 
    { return std::abs(m_bottomright.get_x() - m_lefttop.get_x()); }
    
    const double height() const 
    { return std::abs(m_bottomright.get_y() - m_lefttop.get_y()); }
  
    const double area() const
    { return  width() * height();  }

    const double outline() const
    { return 2.0 * widht() + 2.0 * height(); }
};

#include <iostream>

int main() 
{
    double x,y;
    std::cout << "Koordinaten x und y Punkt A : "; 
    std::cin >> x >> y; 
    Point a(x, y);
 
    std::cout << "Koordinaten x und y Punkt B : ";
    std::cin >> x >> y; 
    Point b(x,y);

    Rect re(a, b);
    std::cout << "Die Rechteckflaeche betraegt " << re.area() << "\n"
              << "Umfang: " << re.outline() << std::endl;
}
;)
 
Danke für eure Antworten!:) Es gibt da jedoch ein Problem, und zwar sollte sowohl die Klasse Punkt wie auch das main so bleiben, wie es ist.

Des weiteren (das hab ich noch nicht programmiert, weil ich die Frage nicht ganz verstehe) wird verlangt, dass man eine public Methode Umfang der Klasse Rechteck erstellen soll, die aber kein Resultat zurückliefert, jedoch als Übergangsparameter eine Referenz auf einen double besitzt, durch den der berechnete Umfang an die aufrufende Instanz übertragen wird.

Also mit einer Refernez erstelle ich ja einfach ein Synonym für etwas, in diesem Falle also den Umfang. Bedeutet das, dass ich eine public Methode Umfang mache, die auf eine andere Methode zugreift (ausserhalb oder in Klasse Rechteck?), wo der eigentliche Umfang berechnet wird? Ich finde, das macht nicht so Sinn, deswegen frage ich.

Aber deine Rechteckt-Klasse hat doch nur einen privaten Konstruktor, das heißt doch, du kannst davon keine neuen Instanzen erstellen, oder?

Ja schon, aber der wiederum nimmt ja Bezug auf die Klasse Punkt. Oder wie würdest du es denn machen?

lg
 
Ich glaub, du hast das noch nicht richtig verstanden.

Code:
// Erzeugen eines Objekts der Klasse "Rechteck" und
// Berechnung des Umfangs und der Flaeche des Rechteckes
Rechteck RE(A,B);

So etwas ist nicht möglich, solange die Klasse ausschließlich einen privaten Konstruktor hat.
 
Hi.
Des weiteren (das hab ich noch nicht programmiert, weil ich die Frage nicht ganz verstehe) wird verlangt, dass man eine public Methode Umfang der Klasse Rechteck erstellen soll, die aber kein Resultat zurückliefert, jedoch als Übergangsparameter eine Referenz auf einen double besitzt, durch den der berechnete Umfang an die aufrufende Instanz übertragen wird.

Also mit einer Refernez erstelle ich ja einfach ein Synonym für etwas, in diesem Falle also den Umfang. Bedeutet das, dass ich eine public Methode Umfang mache, die auf eine andere Methode zugreift (ausserhalb oder in Klasse Rechteck?), wo der eigentliche Umfang berechnet wird? Ich finde, das macht nicht so Sinn, deswegen frage ich.
Nein.

Es soll eine Methode der Klasse Rechteck erstellt werden die "öffentlich" zugreifbar ist. Diese Methode soll allerdings keinen Rückgabewert besitzen - d.h. sie hat den Rückgabetyp void. Das Ergebnis soll vielmehr durch "Call-by-Reference" erfolgen:
C++:
void Umfang(double& ergebnis) {
  ergebnis = ...
}

Rechteck r;

double u;

r.Umfang(u); // <-- Ergebnis steht dann in der Variablen u
Wenn die Methode in Zeile 9 aufgerufen wird, ist der Parameter ergebnis innerhalb der Methode ein "Alias" für die Variable u. Das bedeutet das der Wert der Variablen u innerhalb der Methode Umfang geändert werden kann.

Gruß
 
Ah, ja klar, jetzt ist auch bei mir der Groschen gefallen. Der Konstruktor muss natürlich public sein! Gibts überhaupt Fälle, wo der private ist?

@deepthroat
Stimmt, ich erinnere mich, sonst würde er ja gar nichts bekommen, wenn das & nicht dabeistehen würde, weil double Umfang nicht initialisiert wurde.
Das sollte jetzt richtig sein, funktioiniert auf alle Fälle:).
Kleine Frage noch, das mit dem & für eine Referenz verstehe ich eigtl schon, jedoch gibt es so viele Fälle (hab ich zumindest das Gefühl), wo das nicht gebraucht wird, also das &. Beispielsweise beim Konstruktor vom Rechteck (ok, is vllt ein blödes Beispiel, aber nehmen wir mal das), der besitzt ja auch die Parameter Punkt punkt1 und Punkt punkt2 und da steht ja auch kein & davor, obwohl ich die Punkte erst im main initialisiere.

Code:
#include <iostream>
#include <cmath>
using namespace std;

class Punkt {
private:
double x, y;

public:
Punkt(double X=0, double Y=0) { x=X; y=Y; } //Konstruktor
void set (double X , double Y) { x=X; y=Y; } //Methode
double getX () { return x; } // -"-
double getY () { return y; } // -"-
};

class Rechteck {

private:
Punkt P1,P2; 


public:
	Rechteck(Punkt punkt1, Punkt punkt2) {P1=punkt1, P2=punkt2;};
	double x1, y1, x2, y2, x_länge, y_länge;

	double Fläche(){
		x1=P1.getX();
		y1= P1.getY();
		x2 =P2.getX();
		y2 =P2.getY();
		x_länge = abs(x2-x1);
		y_länge = abs(y2-y1);
		return x_länge*y_länge;};


//double Umfang(umfang);
		void Umfang(double& ergebnis){
		x1=P1.getX();
		y1= P1.getY();
		x2 =P2.getX();
		y2 =P2.getY();
		x_länge = abs(x2-x1);
		y_länge = abs(y2-y1);
			ergebnis = 2*x_länge+2*y_länge;}

	
};

void main() {
// Zwei Variablen vom Typ "Punkt" zur Eingabe der Rechteckkoordinanten
Punkt A, B;
// Eingabe der Koordinaten der Punkte A und B
double x,y;
cout << "Koordinaten x und y Punkt A : "; cin >> x >> y; 
A.set(x,y);
cout << "Koordinaten x und y Punkt B : "; cin >> x >> y; 
B.set(x,y);

// Erzeugen eines Objekts der Klasse "Rechteck" und
// Berechnung des Umfangs und der Flaeche des Rechteckes
Rechteck RE(A,B);
cout << "Die Rechteckflaeche betraegt " << RE.Fläche() << endl;


double Umfang;
RE.Umfang(Umfang);
cout << "Der Umfang des Rechteckes betraegt " << Umfang << endl;

}
 
Ah, ja klar, jetzt ist auch bei mir der Groschen gefallen. Der Konstruktor muss natürlich public sein! Gibts überhaupt Fälle, wo der private ist?

Sicher gibt es die Fälle, immer dann wenn von "außen" kein Objekt instanziert werden soll/darf. Diese Objekte (und damit der Konstruktor) werden dann z.b. in abgeleiteten Klassen oder durch statische Methoden aufgerufen welches ja einen anderen Sichtbarkeitsbereich darstellt (private oder protected).

Zu deinem Problem mit der "Referenz" lies mal nach bei:
  1. Call by Value
  2. Call by Reference

mfg
 
@deepthroat
Stimmt, ich erinnere mich, sonst würde er ja gar nichts bekommen, wenn das & nicht dabeistehen würde, weil double Umfang nicht initialisiert wurde.
Das hat mit der Initialisierung eigentlich wenig zu tun.
Kleine Frage noch, das mit dem & für eine Referenz verstehe ich eigtl schon, jedoch gibt es so viele Fälle (hab ich zumindest das Gefühl), wo das nicht gebraucht wird, also das &. Beispielsweise beim Konstruktor vom Rechteck (ok, is vllt ein blödes Beispiel, aber nehmen wir mal das), der besitzt ja auch die Parameter Punkt punkt1 und Punkt punkt2 und da steht ja auch kein & davor, obwohl ich die Punkte erst im main initialisiere.
Was heißt denn "erst in main"? Die main Funktion ist der Startpunkt für die Programmausführung, d.h. die Punkte werden auf jeden Fall initialisiert, bevor der Konstruktor von Rechteck aufgerufen wird.

Es geht allerdings auch nicht um die Initialisierung. Es geht um die Möglichkeit den Wert von Variablen die als Parameter übergeben werden zu ändern (und außerdem das Kopieren von Objekten beim Funktionsaufruf zu vermeiden).

C++:
void func1(double c) {
  c = 5;
}

void func2(double& c) {
  c = 5;
}

double d = 3;

func1(d);
cout << d << endl; // gibt "3" aus

func2(d);
cout << d << endl; // gibt "5" aus
Funktion func1 benutzt "call-by-value", dabei wird eine Kopie des Wertes des Parameters verwendet; Änderungen wirken sich nur innerhalb der Funktion aus. Eine Kopie beim Funktionsaufruf zu übergeben kann bei Objekten ziemlich teuer sein, deshalb übergibt man eigentlich Objekte generell ungern durch "call-by-value". (Siehe auch die Definition des Konstruktor von DevDevil - er verwendet "call-by-reference" mit const Referenzen)

Funktion func2 verwendet "call-by-reference", es wird keine Kopie erzeugt sondern eine Referenz auf die Variable übergeben. Daher kann der Wert der Variablen innerhalb der Funktion geändert werden.

Grundsätzlich hängt es davon ab was man in der Funktion mit den Parametern tun möchte oder wie "teuer" eine Kopie beim Funktionsaufruf ist, ob man Referenzen verwendet oder nicht.

Gruß
 
Ah, ich glaub ich habs verstanden. Ist folgendes richtig?:

Ich könnte auch, anstatt d nach func2(d) in cout aufzurufen, die Fkt func1(d) aufrufen und ins cout setzen. Der Unterschied besteht darin, dass sich im ersten Fall d tatsächlich verändert hat und m zweiten Fall, dass ich den Rückgabewert der Funktion ausgebe. Ok, was die Fkt. da macht, ist wohl nicht so sinnvoll, aber das ist ja jetzt egal.

C++:
#include <iostream>
using namespace std;

int func1(int c){//call-by-value
	c = 5;
	return c;}

int func2(int& c){//call-by-reference
	c = 5;
	return c;}

int main(){


	int d = 3;
	func1(d);
	cout << d << endl;
	cout << func1(d) << endl;

	func2(d);
	cout << d << endl;
	cout << func2(d) << endl;

	return 0;}
 
Zurück