Referenzen via Elementinitialisierungsliste initialisieren
-
Hallo zusammen,
als C++-Neuling versuche ich schon geraume Zeit, einen Konstruktor für eine Klasse zu erstellen, über den ich zwei Referenzen mit dem Wert zweier Variablen initialisieren kann.
Leider verzweifle ich mittlerweile ein wenig...
Mein Code sieht bis jetzt wie folgt aus:#include <iostream> using namespace std; class Test{ private: float var_x,var_y; float &ref1; float &ref2; public: Test(float&, float&); }; // Konstruktor: Test::Test(float& ref1, float& ref2) : ref1(var_x),ref2(var_y){} int main(){ // Test t1(0.3,0.4); return 0; }
Erst schien mir alles korrekt zu sein / zu funktionieren. Der Compiler übersetzte alles brav ohne Fehlermeldungen.
Als ich dann zu Testzwecken eine Instanz "t1" mit zwei float-Werten erstellen wollte, erhielt ich beim übersetzen folgende Fehlermeldung:In function ‘int main()’: error: no matching function for call to ‘Test::Test(double, double)’ note: candidates are: Test::Test(float&, float&) note: Test::Test(const Test&)
Ich weiß, eine entsprechende Funktion wird tatsächlich nirgends aufgerufen aber warum jetzt "Test::Test(double, double)"?
Ich habe den Konstruktor doch als "(float&,float&)" definiert?
Und ich übergebe beim erzeugen der Instanz doch zwei float-Werte?
Woher kommen also jetzt diese "double"-Meldungen?Oder bin ich jetzt komplett auf dem Holzweg?
Vielen Dank schon mal im voraus!
Gruß,
kyusho
-
Du musst auch floats übergeben (suffix f):
int main(){ Test t1(0.3f,0.4f); return 0; }
-
regel 1: eine temporäre variable (die z.b. entstehen, wenn man rvalues, wie du sie hier hast, verwendet) kann nur an eine konstante referenz gebunden werden.
warum willst du in dieser situation referenzen verwenden? anders gefragt: auf welche variable zeigen ref1 und ref2? richtig: keine.
float a = 1.0, b = 4.2; Test t1 (a, b);
so geht's, und ref1 und ref2 zeigen nun auf a und b.
ich halte es aber nicht unbedingt für eine gute idee, denn wer weiß schon, ob die instanz der klasse nicht länger hält als die float variablen, auf die sie verweist?
was hast du also an dieser stelle gegen kopien?
-
Danke Euch beiden erst einmal, aber:
@Airdamn:
Wenn ich das Suffix 'f' mit übergebe, erhalte ich nun:error: no matching function for call to ‘Test::Test[b](float, float)[/b]’ note: candidates are: Test::Test(float&, float&)
@queer_boy:
Das ist halt eine Übungsaufgabe.
Die Aufgabenstellung verlangt es nun mal, daß ich es über eine Initialisierungsliste mache.
Ich denke auch, daß es in der Praxis sinnvolleres oder einfacheres gibt.
Das mit der Ausgabe (bzw. erst einmal die Erzeugung der Instanz) soll nur eine Überprüfung meinerseits sein, ob's auch klappt.
Aber irgendwie... Wohl nicht...
-
kyusho schrieb:
Danke Euch beiden erst einmal, aber:
@Airdamn:
Wenn ich das Suffix 'f' mit übergebe, erhalte ich nun:error: no matching function for call to ‘Test::Test[b](float, float)[/b]’ note: candidates are: Test::Test(float&, float&)
queer_boy hat ja bereits erwähnt, dass für Referenzparameter nur Variablen als Argumente übergeben werden können und keine Literale (das ginge nur bei Const-Referenzen). Worauf sollte die Referenz denn verweisen, wenn nicht auf eine Variable?
-
kyusho schrieb:
#include <iostream> using namespace std; class Test { private: float var_x, var_y; //var_ würd ich weglassen - ist doch klar, dass es variablen sind ^^ float &ref1; //wozu? float &ref2; //wozu? public: Test(float&, float&); // const float &, const float & - wobei ich hier x und y mit hinschreiben würde, damit man später nicht ausversehen ma verkehrt herum übergibt... }; /* komplett falsch // Konstruktor: Test::Test(float& ref1, float& ref2) : ref1(var_x),ref2(var_y){}*/ //initialisierungsliste: zu_beschreibende_variable (initialisierungswert) Test::Test(const float& _x, const float& _y) : var_x (_x), var_y (_y) {} /*der vollständigkeit halber: variable solltest du aber nur mit nem unterstrich beginnen lassen, wenn danach ein kleiner buchstabe kommt. sonst könnte es passieren, dass du ausversehen nen wert nimmt, den dein compiler irgendwo vorher als makro (#define) definiert bekomman hat...*/
übrigens:
Test t1(0.3,0.4);
geht aber auch - kommt dann aber ne warnung, dass double in float verkürzt wird (sollte zumindest) - das ist hier zwar egal, aber du solltest dir allgemein angewöhnen für float-werte so was zu schreiben:
123.123f
bb
-
Sollte in der "unskillt" version ref1 und ref2 nicht const sein?
-
EDIT:
class Test{ private: float var_x,var_y; float &ref1; float &ref2; public: Test(float&, float&); }; // Konstruktor: Test::Test(float& ref1, float& ref2) : ref1(var_x),ref2(var_y){}
im konstruktor bzw. initilaisierungsliste passt ja mal gar nix zusammen
vll. wollte der OP sowas:
Test::Test(float& ref1, float& ref2) : var_x(ref1), var_y(refl2), ref1(var_x),ref2(var_y){}
-
Hallo zusammen,
da schon mehrfach Fragen der Art "wozu hast Du dies gemacht?", "was bezweckst Du damit?", etc. gestellt wurde (was ich durchaus verstehen und nachvollziehen kann),
hier noch einmal eine kurze Erklärung.Wie schon erwähnt, handelt es sich hierbei um eine Aufgabenstellung. Fest vorgegeben(!) ist folgendes Gerüst (da habe ich auch keinerlei Einfluss drauf):
class Test { private: float &ref1; float &ref2; public: Test(float&, float&); int Ausgabe(); };
Aufgrund dieser Vorgabe soll:
- Ein Konstruktor erstellt werden, "der die Referenzen &ref1 und &ref2 initialisiert".
- &ref1 soll mit dem Wert einer Variablen a initialisiert werden.
- &ref2 soll mit dem Wert einer Variablen b initialisiert werden.Das Ganze soll ausdrücklich über eine Initialisierungsliste erfolgen.
Für mein Verständnis ist ein Variablenkonstruktor &ref(a) (jetzt bitte nicht hauen!) mitunter eine andere Schreibweise für &ref=a.
Daher halt mein Gedanke, zwei Variablen zu deklarieren (float a,b; ) und mit diesen dann die Referenzen &ref1 und &ref2 über eine Initialisierungsliste zu initialisieren.
Also bin ich zu dem folgenden Lösungsansatz gelangt...:class Test { private: float a,b; // Variablen deklarieren... float &ref1; float &ref2; public: Test(float&, float&); int Ausgabe(); }; Test::Test(float& ref1, float& ref2) : ref1(a),ref2(b){} // ...und mit diesen die Referenzen initialisieren.
...aber genau der bereitet mir als Anfänger so einige Kopfzerbrechen...
Ich habe schon alle der genannten Vorschlage und Tipps versucht irgendwie umzusetzen, bin aber irgendwie zu keiner funktionierenden Lösung gekommen..
-
Nur mal zur Klarstellung: Dein Problem kommt nicht von den Referenzen in der Klasse, oder der Initialisierung derselben. Dein Problem entsteht, weil die Parameter für den Konstruktor auch Referenzen sind, die Du aber beim Erzeugen des Objekts an keine Variablen bindest.
Ist die Signatur des Konstruktors vorgeschrieben?
Wenn ja, will der Aufgabensteller womöglich, dass Du die Referenzen in der Klasse nicht mit Variablen der Klasse initialisierst, sondern mit dem, was dort übergeben wird. Aber auch dafür musst Du dem Konstruktor Variablen übergeben.
-
weil die Parameter für den Konstruktor auch Referenzen sind, die Du aber beim Erzeugen des Objekts an keine Variablen bindest.
Ok, das habe ich soweit verstanden. (Jetzt wird mir zumindest einiges klarer - Danke!
)
Ist die Signatur des Konstruktors vorgeschrieben?
So wie ich es verstanden habe, ja. Der vorgegebene Code darf wohl nur erweitert werden.
sondern mit dem, was dort übergeben wird. Aber auch dafür musst Du dem Konstruktor Variablen übergeben.
Also vielleicht so etwas in der Art?:
Test::Test(float& ref1, float& ref2, float a, float b) : ref1(a),ref2(b){}
-
Damit würdest Du ja die Signatur des Konstruktors ändern.
Nein, ich meine folgendes (jedenfalls würde ich die Aufgabenstellung so interpretieren):
int main() { float a; float b; Test t(a, b); // nun soll t.ref1 auf das a hier in main verweisen // dito mit ref2 auf b }
-
Hi
Kann ja sein, dass ich dich (bzw die Aufageb) noch immer nicht verstehe - aber ich versteh es so - obwohl ich es niemals so machen würde...
kyusho schrieb:
Also bin ich zu dem folgenden Lösungsansatz gelangt...:
class Test { private: float a,b; // die brauchst du doch gar nicht, wenn du die referenzen schon hast! oder wozu willst (sollst) du die refernzen überhaupt nutzen? float &ref1; float &ref2; public: Test(float&, float&); int Ausgabe(); /*häh? wie wärs mit => */ void Ausgabe () const; //noch besser wäre natürlich der operator >> aber das wär wahrscheinlich bissl viel ^^ }; Test::Test(float& _ref1, float& _ref2) : ref1 (_ref1), ref2 (_ref2) {}
=>
class Test { private: float &ref1; float &ref2; public: Test(float&, float&); void Ausgabe () const; float& First () {return ref1;} float& Second () {return ref2;} }; Test::Test(float& _ref1, float& _ref2) : ref1 (_ref1), ref2 (_ref2) {} void Test::Ausgabe () const { std::cout << "1. Varialbe: " << ref1 << ", 2.Variable: " << ref2 << std::endl; }
main.cpp: (um dir zu zeigen, warum First () und Second () nicht const sind etc mal ein kleines Beispiel)
int main () { std::cout << "Berechnung von 2*x*y" << std::endl; float a, b; //eingabeaufforderung, fehlerbehandlung etc fehlt... std::cin >> a; std::cin >> b; Test test (a, b); test.First () *= 2; float produkt = test.Second () * test.First (); std::cout << "Ergebnis: " << produkt << std::endl; }
So vll? Sollte eigtl alles gehen ^^
Aber ich versteh das ganze noch immer nicht... das Problem ist ja jz, dass a und b die Werte des Objektes haben... Also wenn man für b 2 angegeben hat ist es am ende trotzdem 4Aber so hab ich die Aufgabe verstanden...
bb
-
Vorab erst einmal: Vielen Dank an alle Beteiligten!
Ich habe jetzt mal anhand von unskilled's Code eine Variante gestrickt, so wie ich sie mir eigentlich ursprünglich vorgestellt habe:
#include <iostream> using namespace std; class Test { private: float &ref1; float &ref2; public: Test(float&, float&); void Ausgabe(); }; Test::Test(float& _ref1, float& _ref2) : ref1(_ref1),ref2(_ref2){} void Test::Ausgabe() { std::cout << "1. Variable: " << ref1 << ", 2. Variable: " << ref2 << std::endl; } int main() { float a = 0.4f; float b = 0.6f; Test test(a,b); test.Ausgabe(); return 0; }
Diese funktioniert wie sie soll aber ganz ehrlich: Da wäre ich von alleine nicht drauf gekommen...
Mir stellt sich zur Zeit noch die Verständnisfrage hinsichtlich des Konstruktors:Test::Test(float& _ref1, float& _ref2) : ref1(_ref1),ref2(_ref2){}
Bis jetzt bin ich eigentlich davon ausgegangen, ein Konstruktor wie der obige sei wie folgt aufgebaut:
[Klassenname]::[Klassenname]([Typ&] [b]Referenz[/b],[Typ&] [b]Referenz[/b]) : [Referenz](zuzuweisende Variable),[Referenz](zuzuweisende Variable){}
Statt dessen ist aber scheinbar folgendes der Fall:
[Klassenname]::[Klassenname]([Typ&] [b]neue Variable[/b],[Typ&] [b]neue Variable[/b]) : [Referenz](zuzuweisende Variable),[Referenz](zuzuweisende Variable){}
Und nun zu meinem Verständnisproblem:
Werden denn mittelsTest::Test([b]float& _ref1, float& _ref2[/b]) : ref1(_ref1),ref2(_ref2){}
nicht eigentlich zwei neue Referenzen(!) namens _ref1 und _ref2 definiert?
Den Rest kann ich soweit nachvollziehen. Nur der Konstruktoraufbau gibt mir echt noch Rätsel auf...
-
Es werden zwei Referenzen definiert, die an die Variablen gebunden werden, die Du beim Aufruf des Konstruktors übergibst. Im Beispiel stehen im Konstruktor also die Variablen a und b aus main() zur Verfügung, nur unter den Namen _ref1 und _ref2. In der Initialisierungsliste werden die Referenzen ref1 und ref2 aus dem Objekt mit den Referenzen _ref1 und _ref2 initialisiert, damit verweisen ref1 und ref2 auch auf a und b aus main(). Es wird also das Ziel der Referenz von der einen in die andere kopiert.
-
Im Beispiel stehen im Konstruktor also die [b]Variablen a und b[/b] aus main() zur Verfügung, [b]nur unter den Namen _ref1 und _ref2[/b]. In der Initialisierungsliste werden die Referenzen ref1 und ref2 aus dem Objekt mit den Referenzen _ref1 und _ref2 initialisiert, damit verweisen ref1 und ref2 auch auf a und b aus main().
Ich glaube, das war der entscheidende Punkt. Ich denke, nun hab' ich's.
Vielen Dank!
Gruß,
kyusho