Operator [] überladen
-
Hallo, ich habe folgende Aufgabe:
1. Programmieren Sie eine Klasse point2D für zweidimensionale Punkte
1.1. Definieren Sie die Membervariablen als private
1.2. Definieren Sie Konstruktoren und wenn nötig einen Destruktor
1.3. Definieren Sie Funktionen, um auf die Membervariablen zuzugreifen
* Konstant
* Veränderlich
2. Definieren Sie eine Klasse triangle2D für Dreiecke in 2D
2.1. Nutzen Sie die Klasse point2D
2.2. Definieren Sie Konstruktoren und wenn nötig einen Destruktor
2.3. Definieren Sie den operator[], um auf die Punkte zuzugreifen
* Konstant
* Veränderlich
2.4. Definieren Sie Memberfunktionen zum Berechnen
* Des Umfangs
* Der FlächeNun weiß ich allerdings nicht genau, wie ich den operator[] überladen soll.
Mein bisheriges Programm sieht so aus:#include<iostream> class point2D { private: float x,y; public: point(float xx=0,float yy=0):x(xx), y(yy) {} float getx() {return x} float gety() {return y} }; class triangle2D { private: point2D A; point2D B; point2D C; public: triangle2D (point A, point B, point C) : A(A), B(B), C(C) {} friend point2D operator[] (const point2D& A); friend point2D operator[] (point2D& A); void perimeter(point2D A, point2D B, point2D C); void area(point2D A, point2D B, point2D C); }; point2D operator[](const point2D& A) {

-
class triangle2d { /** ---*/ public: const point2d& operator[]( int index ) const { /** return point at index */ } };Du kannst auch eine Nonconst-Version anbieten, die eine nonconst-Referenz zurückgibt. Würde ich aber lassen, da dadurch eine gute Portion Kapselung flöten geht.
Außerdem:
1. Programmieren Sie eine Klasse point2D für zweidimensionale Punkte
Punkte selber haben keine Ausdehnung, darum gibt es auch keine zweidimensionalen Punkte.
Es gibt aber Punkte im zweidimensionalen Raum
-
Ich muss leider eingestehen, dass ich das jetzt noch nicht ganz verstanden habe.
Was würde denn bei einer Eingabe von [2] zurückgegeben werden?
-
Du hast bei einem Dreieck 3 Punkte.
1.Punkt: triangle[0]
2.Punkt: triangle[1]
3.Punkt: triangle[2]
Du hast deine drei Punkte in drei verschieden Variablen gepackt.
Du kannst jetzt für index=0 Punkt A zurückgeben usw.
Oder du packst die 3 Punkte in array:class Triangle2D { Point2D points[3]; };Dann könnte operator[] so ausschauen:
const Point2D& Triangle2D::operator[]( int index ) const { assert(index < 3); // Oder einen out_of_bounds-Exception werfen // Oder den Index %3 nehmen // Oder bei index >2 immer points[2] zurückgeben // Such dir das Verhalten aus, das für dich am besten passt return points[index]; }// edit:
Achja: ganz vergessen:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-232010.html
Durchlesen!
-
cppbeginner schrieb:
Was würde denn bei einer Eingabe von [2] zurückgegeben werden?
Normalerweise gibt ein op[] bei einer Liste von Elementen das n-te Element zurück wenn er mit
[n]aufgerufen wird. Bei einem N-eck würde ich daher davon ausgehen, dass der op[], aufgerufen mit den Werten 0, 1,..., N-1 den jeweiligen Eckpunkt zurückgibt.
-
1. Const-Correctness
Grundsätzlich sollten Methoden, welche das Objekt nicht ändern, als const bezeichnet werden. Am obigen Beispiel:
class point2D { // ... float getx() const {return x}; // statt: float getx() {return x} float gety() const {return y} // statt: float gety() {return y} // ... };2. operator[]
Die Methode X operator[](Y) tut genau das, was man ihr aufgibt.
Grundsätzlich sollte sie was zurückgeben (X). Operatoren kann man grob gesagt mit allen möglichen Funktionalitäten überladen (so geschehen auch bei std::cout << ...).
Man kann Operatoren auch direkt aufrufen:
foo[14] // entspricht dem Aufruf: foo.operator[](14); // oder ... foo += bar; // entspricht: foo.operator+=(bar);Globale Operatorüberladung funktioniert ähnlich. Da ich gerade aber sehe, dass l'abra d'or bereits ausführlich geantwortet hat, verweise ich mal darauf.
3. Kapselung (Off-Topic)
Du kannst auch eine Nonconst-Version anbieten, die eine nonconst-Referenz zurückgibt. Würde ich aber lassen, da dadurch eine gute Portion Kapselung flöten geht.
Auf die Gefahr hin, dass ich jetzt einen Nebenschauplatz eröffne, aber insbesondere die Klasse point2D lässt eine Notwendigkeit eine Kapselung -- meiner Meinung nach -- nicht erkennen.
Im Grunde könnte man alle Attribute genauso public deklarieren, auch wenn es der Aufgabenstellung mit den entsprechenden Zugriffsmethoden widerspricht.
Es ist wesentlich intuitiver die Attribute zum Teil des Interfaces werden zu lassen. Der Gefahr Inkonsistenzen zu erzeugen, setzt man sich hier nicht aus.
#if !defined(CPPDE_POINT2D_H__INCLUDED) #define CPPDE_POINT2D_H__INCLUDED struct Point2D { float x; float y; explicit Point2D(float x = 0.f, float y = 0.f) : x(x), y(y) { } }; #endifPoint2d p; p.x = 1.0 std::cout << p.y << std::endl;Grüße ... Heiko
-
bwbg schrieb:
Du kannst auch eine Nonconst-Version anbieten, die eine nonconst-Referenz zurückgibt. Würde ich aber lassen, da dadurch eine gute Portion Kapselung flöten geht.
Auf die Gefahr hin, dass ich jetzt einen Nebenschauplatz eröffne, aber insbesondere die Klasse point2D lässt eine Notwendigkeit eine Kapselung -- meiner Meinung nach -- nicht erkennen.
Aber wir wollen den operator[] ja nicht für Point2D sondern für Triangle2D.
Und da muss man sich das genauer überlegen, ob man den Point wirklich per non-const-Referenz zurückgeben will, und damit ein Verändern des Punktes hinter dem Rücken von Triangle2D erlauben.
Z.B. wenn man einen Punkt im Dreieck verändern will, kann das im setter mehrere Nebeneffekte haben:
zuerst prüfen, ob der zu setzende Punkt nicht mit einem der beiden anderen identisch ist (Resultat wäre eine Gerade, komisches Verhalten wäre die Folge, k.A. ob man das will)
-> Punkt wird NICHT gesetzt!
Fläche aktualisieren und cachen.
usw. (ist sicher nicht soo gut noch mehr Nebeneffekte zuhaben, aber möglich ist es...)
All das hintergeht man, wenn man dem operator[] eine nicht-const-Referenz zurückgeben lässt.
-
Also ich komme mit dem ganzen zeug hier einfach nicht zurecht. Mein Programm sieht jetzt momentan so aus:
#include<iostream> using namespace std; class point2D { private: float x,y; public: point2D(float xx=0,float yy=0):x(xx), y(yy) {} float getx() const {return x;} float gety() const {return y;} }; class triangle2D { private: point2D A; point2D B; point2D C; public: triangle2D (point2D A, point2D B, point2D C) : A(A),B(B),C(C) {} friend const point2D operator[](int index) const; void perimeter(point2D points); void area(point2D points); }; const point2D& operator[](int index) const{ assert (index<3); if (index==0) return A; else if (index==1) return B; else if (index==2) return C; }Aber wenn ich das kompaliere kommen folgende Fehlermeldungen mit denen ich nix anfangen kann:
triangle2D.cpp:21: Fehler: non-Elementfunktion »const point2D operator[](int)« kann nicht CV-Qualifizierer haben
triangle2D.cpp:21: Fehler: »const point2D operator[](int)« muss eine nichtstatische Elementfunktion sein
triangle2D.cpp:26: Fehler: non-Elementfunktion »const point2D& operator[](int)« kann nicht CV-Qualifizierer haben
triangle2D.cpp:26: Fehler: »const point2D& operator[](int)« muss eine nichtstatische Elementfunktion seinKann sein das mein Programm auch volkommen falsch ist, aber ich steig einfach nicht wirklich dahinter.

-
was hat die freie funktion da zu suchen? vermutlich willst du eher den op[] implementieren, was eigentlich in die .cpp-datei gehört, und wofür dann der Qualifizierer fehlt:
const point2D& triangle2D::operator[](int index) const{ //<<triangle2D fehlte! assert (index<3); if (index==0) return A; else if (index==1) return B; else if (index==2) return C; }operator[] ist eine Memberfunktion wie jede andere auch, nur der Name sieht etwas anders aus.
-
Ok, jetzt habe ich es so geändert wie du gesagt hat, aber jetzt meckert er gerade rum, weil das triangle2D da steht.
class triangle2D { private: point2D A; point2D B; point2D C; public: triangle2D (point2D A, point2D B, point2D C) : A(A),B(B),C(C) {} const point2D& triangle2D::operator[](int index) const { assert(index<3); if (index==0) return A; else if (index==1) return B; else if (index==2) return C; } void perimeter(point2D points); void area(point2D points); };Fehler:
triangle2D.cpp:21: Fehler: zusätzliche Qualifizierung »triangle2D::« an Element »operator[]«Tut mir leid falls das alles dumme Fragen sind

-
cppbeginner schrieb:
Ok, jetzt habe ich es so geändert wie du gesagt hat, aber jetzt meckert er gerade rum, weil das triangle2D da steht.
Du hast es nicht so geändert

operator[]() soll eine Member-FUnktion werden. Wie du normale Member-Funktionen deklarierst weißt du ja. Nämlich OHNE dem Klassen-Qualifizierer.
Den brauchst du aber, wenn du die Funktion definierst (die Implementierung), wenn diese außerhalb der Klassendefinition geschehen soll.
-
Aha. Ok, dass hab ich jetzt glaub ich gerafft

Vielen Dank für eure Hilfe und für eure Geduld!!!!!
-
Hier bin ich doch noch mal

Wenn ich, wie in der Aufgabe gefordert, den Operator[] noch mal veränderlich mache, dann muss ich den einfach noch mal überladen und lasse aber das const weg oder?
Dann noch eine andere Frage. Kann ich den Operator jetzt auch sinnvoll nutzen um Fläche und Umfang auszurechnen?
Ich habe den nicht mehr verwendet, sondern das wie folgt gemacht:float point2D::distance(point2D A) { return sqrt((A.getx()-x)*(A.getx()-x)+(A.gety()-y)*(A.gety()-y)); } void triangle2D::perimeter() { float perimeter=A.distance(B)+B.distance(C)+A.distance(C); cout<<"The perimeter of Triangle ABC is: "<< perimeter <<endl;; } void triangle2D::area() { float gamma=acos((B.distance(C)*B.distance(C)+A.distance(C)*A.distance(C)-A.distance(B)*A.distance(B))/(2*B.distance(C)*A.distance(C))); float area=B.distance(C)*A.distance(C)*sin(gamma)/2; cout<<"The area of Triangle ABC is: "<<area<<endl; }Mir leuchtet aber auch nicht ganz ein, wie ich das mit dem [] besser einbringen könnte, so dass eine effektivere Lösung dabei herauskommt.
-
cppbeginner schrieb:
Mir leuchtet aber auch nicht ganz ein, wie ich das mit dem [] besser einbringen könnte, so dass eine effektivere Lösung dabei herauskommt.
Garnicht. Wenn du perimeter und area als Methoden der Klasse machen sollst ist das ok so. Wenn du allerdings ne freie Funktion draus machen sollst die jeweils nur ein Dreieck als Argument bekommst dann musst du halt den op[] benutzen um die Eck-Koordinaten zu bekommen.
-
Alles klar. Vielen Dank
