friend Methoden in Template Klassen

Schnelle objektorientierte, kompilierende Programmiersprache.
Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Di Jan 19, 2021 3:35 pm

MiCsoft hat geschrieben:
Di Jan 19, 2021 1:26 pm
Die meisten Menschen lernen, was sie machen dürfen. Sie stecken einen Weg ab, wie man das Mienenfeld durchqueert. Aber wehe das Ziel liegt woanders.
Ja das stimmt schon. Doch wenn man gar kein Mienenfeld hat, lässt es sich doch sicherlich netter umherlaufen :D
Möglich, nur hat das dann nichts mit Programmierung zu tun. :-D
MiCsoft hat geschrieben:
Di Jan 19, 2021 1:26 pm
Inzwischen habe ich ehrlich gesagt auch mein Hirn ausgeschaltet :roll: Da ich mich erst mit Templates und Operatoren beschäftigt habe, dachte ich naja so schwer kann es nicht sein beides nun zu verbinden =D
Ist es auch nicht... Aber man kann nicht alles auswendig kennen und manche Syntaxbesonderheiten muss ich genauso googlen, weil ich das auch nicht jeden Tag mache.
MiCsoft hat geschrieben:
Di Jan 19, 2021 1:26 pm
flush() brauch ich das auch unter Linux? Dachte das bräuchte ich unter Linux (Ubuntu) gar nicht =D
Niemand garantiert einen Flush, wenn Du nicht selbst einen setzt oder die Größe des Buffers auf Null setzt.
Jeder Flush kostet Zeit. Und C++ gibt in vielen Bereichen keine Garantien, wenn das dazu führen könnte, dass Software erzwungenermaßen langsamer laufen müsste, als nötig.
MiCsoft hat geschrieben:
Di Jan 19, 2021 1:26 pm
Nur habe ich ja jetzt das Problem das ich cout << ListNode nicht schreiben kann =(
Mehr Code. Mehr Erwartungshaltung, mehr Information, was nicht geht.
MiCsoft hat geschrieben:
Di Jan 19, 2021 1:26 pm
no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘ListNode<int>’)
Hab es auch wieder mit dem Prototyp versucht doch da weiß ich nicht mal wie ich den unique_ptr vernünftig hingeschrieben bekomme. Da er die Innere Klasse Node nicht kennt muss ich diese ja mit angeben also so:
ListNode::Node doch da kommen dann wieder 100 Fehler =(

so hatte ich es außerhalb der .h
Außerhalb?
Üblich ist, dass die Template-Deklarationen in der Header-Datei sind... muss nicht, wenn man das Template nur in einer .cpp-Datei braucht, aber das ist eher untypisch, sonst würde man ja kein Template machen.
MiCsoft hat geschrieben:
Di Jan 19, 2021 1:26 pm
emplate argument 1 is invalid
unique_ptr< ListNode::Node > *ptr = &other.anfang;
ListNode ist ein Template, Du musst einen Typen angeben. Also ListNode<int> oder eben ListNode<T>. ListNode::Node existiert nicht.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Di Jan 19, 2021 4:26 pm

Ich weiß nicht mehr weiter.
Hier mal der ganze Code. Vielleicht kommt bei dir ja gar keine Fehlermeldung =D
Die komplette .h Datei =)

Code: Alles auswählen

#include <memory>
#include <iostream>

using namespace std;

template<class T>
class ListNode {
private:
	class Node {
	private:
		T value;
		unique_ptr<Node> next;
	public:
		Node(T value = { }, unique_ptr<Node> next = nullptr) :
				value(value), next(move(next)) {

		}
		unique_ptr<Node>& getNext() {
			return next;
		}
		void setNext(unique_ptr<Node> next) {
			this->next = move(next);
		}
		T getValue() const {
			return value;
		}
		void setValue(T value) {
			this->value = value;
		}
	};
	unique_ptr<Node> anfang;
	void recInsert(unique_ptr<Node> &s, T value);
	void rekCopy(const unique_ptr<Node> &pAct);
	void recPrint(const unique_ptr<Node> &s);
public:
	ListNode();
	virtual ~ListNode() = default;
	ListNode(const ListNode<T> &other);
	ListNode(ListNode<T> &&other);
	ListNode<T>& operator=(const ListNode<T> &other);
	ListNode<T>& operator=(ListNode<T> &&other);
	void insert(T value);
	void print();
	ostream& operator << (ostream& os) {
		unique_ptr< Node > const *ptr = &anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					os.flush();
					ptr = &(*ptr)->getNext();
				}
			return os;
	}

	friend ostream& operator<<(ostream& os, const ListNode<T> &other);
};

template<class T>
ostream& operator << (ostream& os, const ListNode<T> &other) {
		unique_ptr< ListNode::Node > const *ptr = &other.anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					os.flush();
					ptr = &(*ptr)->getNext();
				}
			return os;
	}

template<class T>
ListNode<T>::ListNode() :
		anfang(nullptr) {
}

template<class T>
ListNode<T>::ListNode(const ListNode<T> &other) :
		anfang(nullptr) {
	rekCopy(other.anfang);
}

template<class T>
ListNode<T>::ListNode(ListNode<T> &&other) :
		anfang(move(other.anfang)) {
}

template<class T>
ListNode<T>& ListNode<T>::operator =(const ListNode<T> &other) {
	if (this != &other) {
		anfang = nullptr;
		rekCopy(other.anfang);
	}
	return *this;
}

template<class T>
ListNode<T>& ListNode<T>::operator =(ListNode<T> &&other) {
	anfang = move(other.anfang);
	return *this;
}

template<class T>
void ListNode<T>::recInsert(unique_ptr<Node> &s, T value) {
	if (s->getNext() == nullptr)
		s->setNext(move(unique_ptr<Node>(new Node { value })));
	else
		recInsert(s->getNext(), value);
}

template<class T>
void ListNode<T>::insert(T value) {
	if (anfang == nullptr)
		anfang = move(unique_ptr<Node>(new Node { value }));
	else
		recInsert(anfang, value);
}

template<class T>
void ListNode<T>::rekCopy(const unique_ptr<Node> &pAct) {
	if (pAct != nullptr) {
		insert(pAct->getValue());
		rekCopy(pAct->getPNext());
	}
}

template<class T>
void ListNode<T>::print() {
	recPrint(anfang);
}

template<class T>
void ListNode<T>::recPrint(const unique_ptr<Node> &s) {
	if (s != nullptr) {
		cout << s->getValue() << " ";
		recPrint(s->getNext());
	}
}

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Di Jan 19, 2021 6:51 pm

Ich habe keinen Code, das zu instanziieren, aber es kompiliert ja auch nicht.

Hier der Code mal kommentiert und (ohne irgendwas zu instanziieren) kompilierfähig.

Code: Alles auswählen

#include <memory>
#include <iostream>

// kein using namespace in Headerdateien benutzen!
using namespace std;  

// für die Deklaration von operator << muss ListNode vorab deklariert werden
template< typename T>
class ListNode;

// für die Deklaration als friend muss von operator << vorab deklariert werden
template< typename T >
ostream& operator<< (ostream& os, const ListNode<T> &other);

template<class T>
class ListNode {
private:
	class Node {
	private:
		T value;
		unique_ptr<Node> next;
	public:
		Node(T value = { }, unique_ptr<Node> next = nullptr) :
				value(value), next(move(next)) {

		}
		unique_ptr<Node>& getNext() {
			return next;
		}
		void setNext(unique_ptr<Node> next) {
			this->next = move(next);
		}
		T getValue() const {
			return value;
		}
		void setValue(T value) {
			this->value = value;
		}
	};
	unique_ptr<Node> anfang;
	void recInsert(unique_ptr<Node> &s, T value);
	void rekCopy(const unique_ptr<Node> &pAct);
	void recPrint(const unique_ptr<Node> &s);
public:
	ListNode();
	virtual ~ListNode() = default;
	ListNode(const ListNode<T> &other);
	ListNode(ListNode<T> &&other);
	ListNode<T>& operator=(const ListNode<T> &other);
	ListNode<T>& operator=(ListNode<T> &&other);
	void insert(T value);
	void print();
  
  // das hier definiert
  // ListNode<T> << ostream &
  // und ist vermutlich nicht das, was Du willst.
	ostream& operator << (ostream& os) {
		unique_ptr< Node > const *ptr = &anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					os.flush();
					ptr = &(*ptr)->getNext();
				}
			return os;
	}
	
	// Wie zuvor beschrieben: operator<< wird ein Template, also <> dahinter.
	friend ostream& ::operator<<<> (ostream& os, const ListNode<T> &other);
};

template<class T>
ostream& operator << (ostream& os, const ListNode<T> &other) {
  // Hier kommt ein typename davor, weil Du behauptest, dass ListNode<T> etwas beinhaltet, was Node heißt,
  // aber da T ja nicht bekannt ist, kann der Compiler nicht deduktieren, was Node sein soll. Du erklärst
  // hier, dass es sich um einen Typnamen handelt.
  // Du verwendest hier const hinter dem Typen ("East Const"). Vermutlich von mir kopiert. 
  // Überall sonst verwendest Du const hinter dem betreffenden Teil. ("West const"). Semantisch ist das identisch.
  // West-Const wird meist gelehrt, ist eher traditionell, es funktioniert aber nur in genau diesem Ausnahmefall.
  // Alles andere ist East Const. Siehe als Beispiel getValue, Zeile 33
  //
		unique_ptr< typename ListNode<T>::Node > const *ptr = &other.anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					os.flush();
					ptr = &(*ptr)->getNext();
				}
			return os;
	}

template<class T>
ListNode<T>::ListNode() :
		anfang(nullptr) {
}

template<class T>
ListNode<T>::ListNode(const ListNode<T> &other) :
		anfang(nullptr) {
	rekCopy(other.anfang);
}

template<class T>
ListNode<T>::ListNode(ListNode<T> &&other) :
		anfang(move(other.anfang)) {
}

template<class T>
ListNode<T>& ListNode<T>::operator =(const ListNode<T> &other) {
	if (this != &other) {
		anfang = nullptr;
		rekCopy(other.anfang);
	}
	return *this;
}

template<class T>
ListNode<T>& ListNode<T>::operator =(ListNode<T> &&other) {
	anfang = move(other.anfang);
	return *this;
}

template<class T>
void ListNode<T>::recInsert(unique_ptr<Node> &s, T value) {
	if (s->getNext() == nullptr)
		s->setNext(move(unique_ptr<Node>(new Node { value })));
	else
		recInsert(s->getNext(), value);
}

template<class T>
void ListNode<T>::insert(T value) {
	if (anfang == nullptr)
		anfang = move(unique_ptr<Node>(new Node { value }));
	else
		recInsert(anfang, value);
}

template<class T>
void ListNode<T>::rekCopy(const unique_ptr<Node> &pAct) {
	if (pAct != nullptr) {
		insert(pAct->getValue());
		rekCopy(pAct->getPNext());
	}
}

template<class T>
void ListNode<T>::print() {
	recPrint(anfang);
}

template<class T>
void ListNode<T>::recPrint(const unique_ptr<Node> &s) {
	if (s != nullptr) {
		cout << s->getValue() << " ";
		recPrint(s->getNext());
	}
}
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Di Jan 19, 2021 7:21 pm

Vielen Dank so läuft es nun.

Jetzt hätte ich aber noch ein paar Fragen.
Wieso muss ich für die Deklaration als friend vom operator << das ganze vorab deklarieren? Liegt es daran das es ein Template ist?

Das mit dem const verstehe ich eh nicht so ganz. Mir ist nicht klar wieso man in der Funktion operator<< den Zeiger ptr const macht und Ihn dann trotzdem verändern kann? Wieso wir Ihn const machen müssen leuchtet mir ein, das Objekt was als Referenz rein kommt ist ja auch const und kann damit nicht verändert werden. Somit muss eben auch ein Zeiger auf ein Datenelement in diesem const Objekt const sein.
Wieso darf der Zeiger aber seine Adresse durch die Zeile:

Code: Alles auswählen

ptr = &(*ptr)->getNext();
ändern?

Danke für deine super Hilfe =)

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Di Jan 19, 2021 7:51 pm

MiCsoft hat geschrieben:
Di Jan 19, 2021 7:21 pm
Jetzt hätte ich aber noch ein paar Fragen.
Wieso muss ich für die Deklaration als friend vom operator << das ganze vorab deklarieren? Liegt es daran das es ein Template ist?
Du musst alles, was Du irgendwie verwenden willst, vorher als existent deklarieren und damit gibst Du ihm eben auch einen Typ. Sonst sagt der Compiler, dass er damit nichts anfangen kann.
Manchmal ist das etwas nervig, aber wenn es nicht vorher deklariert würde, wüsste er ja nicht, was das soll.
MiCsoft hat geschrieben:
Di Jan 19, 2021 7:21 pm
Das mit dem const verstehe ich eh nicht so ganz. Mir ist nicht klar wieso man in der Funktion operator<< den Zeiger ptr const macht und Ihn dann trotzdem verändern kann? Wieso wir Ihn const machen müssen leuchtet mir ein, das Objekt was als Referenz rein kommt ist ja auch const und kann damit nicht verändert werden.

Somit muss eben auch ein Zeiger auf ein Datenelement in diesem const Objekt const sein.
Wieso darf der Zeiger aber seine Adresse durch die Zeile:

Code: Alles auswählen

ptr = &(*ptr)->getNext();
ändern?
Weil das Objekt const ist, der Zeiger aber nicht.

Und schon sind wir wieder bei der East-Const / West-Const Frage.
Ich verweise mal auf's Wiki: cpp:const:start
MiCsoft hat geschrieben:
Di Jan 19, 2021 7:21 pm
Danke für deine super Hilfe =)
Dafür ist das Forum da.

Darf man fragen, mit welcher Motivation Du C++ lernst?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Mi Jan 20, 2021 4:18 pm

Hallo,

das mit dem East-Const / West-Const muss ich mir dringend anschauen.

Das ist echt Klasse das es Heutzutage so etwas gibt :-) Das Internet ist eben auch für vieles sehr schön :-) (Klar es gibt auch vieles schlechtes!)

Klar darfst du fragen. Ich Studiere derzeit Informatik. Dort haben wir erst Java gelernt. Das fand ich sehr angenehm und hat auch super viel Spaß gemacht.
Doch ich hab mich schon immer gefragt wie ein Betriebssystem funktioniert etc. wie geht das alles eben =D und dafür benötigt man C/C++.
Denke auch das ich das ganze Thema zu sehr überstürzt habe. Naja wir haben das alles eben auch in Java gelernt und nun dachte ich, es wäre nicht so schwer von Java zu C/C++. Falsch gedacht, dabei heißt es kann man eine Programmiersprache lernt sich eine weitere leichter hehe.
Kontrollstrukturen etc. sind natürlich weites gehend identisch.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Mi Jan 20, 2021 5:20 pm

MiCsoft hat geschrieben:
Mi Jan 20, 2021 4:18 pm
das mit dem East-Const / West-Const muss ich mir dringend anschauen.
Das ist echt Klasse das es Heutzutage so etwas gibt :-) Das Internet ist eben auch für vieles sehr schön :-) (Klar es gibt auch vieles schlechtes!)
Das es sowas gibt, liegt in dem Fall daran, dass ich es geschrieben habe. proggen.org lebt davon, dass Leute sich Zeit und Mühe mahen. Ich habe mit sowas im Studium angefangen - wenn ich Dinge ausformulieren und erklären muss, muss ich es verstanden haben.
Du bist herzlich eingeladen, Deine Erkenntnisse hier auszuformulieren und weiter zu geben.
MiCsoft hat geschrieben:
Mi Jan 20, 2021 4:18 pm
Denke auch das ich das ganze Thema zu sehr überstürzt habe. Naja wir haben das alles eben auch in Java gelernt und nun dachte ich, es wäre nicht so schwer von Java zu C/C++. Falsch gedacht, dabei heißt es kann man eine Programmiersprache lernt sich eine weitere leichter hehe.
Mit etwas Erfahrung in C++ bist Du gut gerüstet für viele andere Ideen.
MiCsoft hat geschrieben:
Mi Jan 20, 2021 4:18 pm
Kontrollstrukturen etc. sind natürlich weites gehend identisch.
Ähh... da kommt noch was. :-)

Ich habe im Studium Tutorien gegeben in C und C++. Und das Feedback war häufig, dass die Leute während meines Tutoriums erklärten, dass sie jetzt verstanden haben, was sie vorher in Java getan haben.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Antworten