const Char* geht nicht
-
Streamer schrieb:
Zumindest integriert es sich schlecht in meine Library weshalb ich die Standard Library nach Möglichkeit nicht verwende.
Furchtbar schlechte Idee.
When in Rome do as the Romans do.
-
Manchaml möchte man aber auch eine Zeichenkette Zeichen für Zeichen auswerten können. Z.B. wenn man eine Xml-Datei parst. So brauche ich nicht den gesamten String/Vektor an die Funktionen zu übergeben sondern nur den Zeiger auf die aktuelle Position.
void ÜberspringeLeerzeichen(Char*& c) { while (*c == L' ') { ++c; } } int main() { Char* c = L"Hier sollen warum auch immer alle Leerzeichen übersprugen werden!"; ÜberspringeLeerzeichen(c); }
-
Wieso muss nochmal alles von einer gemeinsamen Basisklasse abgleitet werden?
-
Streamer schrieb:
Manchaml möchte man aber auch eine Zeichenkette Zeichen für Zeichen auswerten können. Z.B. wenn man eine Xml-Datei parst. So brauche ich nicht den gesamten String/Vektor an die Funktionen zu übergeben sondern nur den Zeiger auf die aktuelle Position.
void ÜberspringeLeerzeichen(Char*& c) { while (*c == L' ') { ++c; } } int main() { Char* c = L"Hier sollen warum auch immer alle Leerzeichen übersprugen werden!"; ÜberspringeLeerzeichen(c); }Und das kannst du mit std::string nicht?
-
Streamer schrieb:
Manchaml möchte man aber auch eine Zeichenkette Zeichen für Zeichen auswerten können. Z.B. wenn man eine Xml-Datei parst. So brauche ich nicht den gesamten String/Vektor an die Funktionen zu übergeben sondern nur den Zeiger auf die aktuelle Position.
Schau dir mal das Konzept "Iterator" an.
Das ist genau das was man in so einer Situation verwendet.
-
314159265358979 schrieb:
Und das kannst du mit std::string nicht?
Ja doch natürlich, ich will es eben aber auch mit meiner Char-Klasse können. Zudem müsste ich mal testen ob das ganze mit einem std::wstring noch genauso schnell ist.
camper schrieb:
Wieso muss nochmal alles von einer gemeinsamen Basisklasse abgleitet werden?
Damit ich anstatt
class ResourceManager { protected: std::vector<MyClass1> myClass1Storage; std::vector<MyClass2> myClass2Storage; std::vector<MyClass3> myClass3Storage; ... std::vector<MyClass100> myClass100Storage; };dies hier schreiben kann
class ResourceManager { protected: std::vector<MyBaseClass*> myClassStorage; };und wegen der Erweiterbarkeit natürlich.
-
Streamer schrieb:
Ja doch natürlich, ich will es eben aber auch mit meiner Char-Klasse können. Zudem müsste ich mal testen ob das ganze mit einem std::wstring noch genauso schnell ist.
Die Iterationsgeschwindigkeit ist unabhängig vom darunterliegenden Typ :p
-
314159265358979 schrieb:
Die Iterationsgeschwindigkeit ist unabhängig vom darunterliegenden Typ :p
Das ist ja schonmal gut zu wissen. Ob das ganze aber schneller ist wie ein roher Zeiger den ich über ein Array rattern lasse bezweifel ich. Es wird sich wahrscheinlich beides nicht viel geben.
Was ich halt vermeiden möchte ist ein absoluter Typen-Mischmasch. Da mal String und Char dort wieder std::wstring bzw. wchar_t. An anderer Stelle wieder const wchar_t* wegen Win32-API. Wenn ich sowieso eine Char/String Klasse brauche nehme ich auch die.
-
Streamer schrieb:
Was ich halt vermeiden möchte ist ein absoluter Typen-Mischmasch. Da mal String und Char dort wieder std::wstring bzw. wchar_t. An anderer Stelle wieder const wchar_t* wegen Win32-API. Wenn ich sowieso eine Char/String Klasse brauche nehme ich auch die.
Dann wrappe std::string nur. Verdopple keine Funktionalitaet. Und so kannst du auch easy in deinem Resourcen Manager eine Polymorphe Stringklasse haben aber nach aussen fast nur std::string hergeben.
-
Streamer schrieb:
Aber wenn ich sowieso schon alle Klassen wrappe dann kann ich sie auch gleich (zumindest im Fall der String-Klasse) selber implementieren, zumal ich in gewissen Scenarien mit der std::wstring Implementation eh nicht zufrieden bin. Z.B. beim Auffinden von Substrings in sehr langen Zeichenketten. Hier habe ich nun die ideale Gelegenheit z.B. den Boyer-Moore-Algorithmus in die Substring-Funktion zu integrieren.
Genau das kannst du wunderbar mit einer Wrapperklasse um
std::wstringtun. Die STL-Klassen bieten alle eine Iterator-Schnittstelle an, mit der du sehr ähnlich wie mit Zeigern arbeiten kannst, nur auf einer höheren Abstraktionsebene. Du kannst beliebige Algorithmen definieren, die auf einemstd::wstringoperieren. Das ist noch lange kein Grund, all die Mühseligkeiten (manuelle Speicherverwaltung, Kopiersemantik, separate Grössenspeicherung) eineswchar_t*auf sich zu nehmen.Streamer schrieb:
Außerdem finde ich den Codestyle der Standard Library zusammen mit dem Template-Fetischismus nicht sonderlich ansehlich. Zumindest integriert es sich schlecht in meine Library weshalb ich die Standard Library nach Möglichkeit nicht verwende.
Arbeite nicht gegen die Standardbibliothek, sondern mit ihr. Du kannst ja immer noch kapseln. Aber die STL ist konzeptionell wirklich enorm durchdacht, du solltest dich nicht von den Templates abschrecken lassen, nur weil du bisher vor allem andere Abstraktionsmechanismen (Vererbung und Polymorphie) kennengelernt hast.
-
Streamer schrieb:
camper schrieb:
Wieso muss nochmal alles von einer gemeinsamen Basisklasse abgleitet werden?
Damit ich anstatt
class ResourceManager { protected: std::vector<MyClass1> myClass1Storage; std::vector<MyClass2> myClass2Storage; std::vector<MyClass3> myClass3Storage; ... std::vector<MyClass100> myClass100Storage; };dies hier schreiben kann
class ResourceManager { protected: std::vector<MyBaseClass*> myClassStorage; };und wegen der Erweiterbarkeit natürlich.
Und was kann diese Basisklasse? Und wie greifst du dann auf die Einzelelemente zu? dynamic_cast oder typeid-Orgien?
Ich hatte eigentlich den Eindruck, dass Container aus Basisklassenzeigern in C++ schon seit 15 Jahren aus der Mode gekommen sind. Weil sie langsam und unwartbar sind, und ganz allgemein nicht wirklich funktionieren. (Genauer: Container, in denen die Einzelelemente nur zu dem Zweck, sie in Containern zu speichern, von einer Basisklasse abgeleitet werden).
-
camper schrieb:
Und was kann diese Basisklasse?
Die Basisklasse selber natürlich nicht viel, aber da sind auch noch weitere Zwischenklassen vorhanden.
camper schrieb:
Und wie greifst du dann auf die Einzelelemente zu? dynamic_cast oder typeid-Orgien?
Weder noch. Ein static_cast sollte doch reichen, oder nicht?
camper schrieb:
Ich hatte eigentlich den Eindruck, dass Container aus Basisklassenzeigern in C++ schon seit 15 Jahren aus der Mode gekommen sind. Weil sie langsam und unwartbar sind, und ganz allgemein nicht wirklich funktionieren. (Genauer: Container, in denen die Einzelelemente nur zu dem Zweck, sie in Containern zu speichern, von einer Basisklasse abgeleitet werden).
Das mag ja sein. Ich richte mich aber nicht nach der Mode sondern nach der Aufgabenstellung/Zielsetzung. Es nützt mir wenig ein absolut stilistisch korrektes Programm zu schreiben das dann aber nicht die Aufgaben erfüllt für die es vorgesehen war.
Mal davon abgesehen, dass sich der Code seit ich Container mit Basisklassenzeigern verwende um sicherlich ca. 50% verrigert hat, wenn nicht noch mehr. Soviel dann auch zur Wartbarkeit. Das Programm ist nun deutlich flexibler kann z.B. ohne neukompilieren der Library erweitert werden. Von langsam kann auch keine Rede sein. Im Gegenteil ich bin erstaunt wie schnell das Programm läuft. Warum das ganze nicht funktionieren sollte ist mir auch ein Rätsel.
Aber wenn du mir eine alternative Lösung bieten kannst die das gleiche leisten kann nur her damit.
-
Streamer schrieb:
Weder noch. Ein static_cast sollte doch reichen, oder nicht?
Nein, du kennst ja den dynamischen Typen der Zeiger nicht. Also die konkrete abgeleitete Klasse, deren Objekt sich hinter dem Basisklassenzeiger verbirgt. Du hast nur ein
Base*. Wie willst du dir sicher sein, dass das auf einDerived1und nichtDerived2zeigt? Wenn du mitstatic_castfalsch castest, ist die Hölle los.Haben deine Klassen echt keine virtuellen Funktionen? Was bringt dann die Abstraktion als gemeinsame Basisklasse, und vor allem wie unterscheidest du zwischen den unterschiedlichen abgeleiteten Klassen?
-
Streamer schrieb:
camper schrieb:
Und wie greifst du dann auf die Einzelelemente zu? dynamic_cast oder typeid-Orgien?
Weder noch. Ein static_cast sollte doch reichen, oder nicht?
Und woher weißt du, wohin du die Elemente casten mußt? Das dürfte dann auf irgendeine Art von Fallunterscheidung hinauslaufen.
-
Alternativ ginge eventuell auch ein
vector<boost::any>. Dadurch müssen die Klassen keine gemeinsame Basisklasse haben, welche eine Beziehung darstellen würde, die gar nicht existiert. Allerdings ist eine solche Lösung, egal ob mit any oder gemeinsamer Basisklasse, in der Regel ein Zeichen, dass es designtechnisch besser geht. Da ich dein Design nicht kenne, kann ich das in deinem Fall aber natürlich nicht beurteilen.
-
Streamer schrieb:
Was ich halt vermeiden möchte ist ein absoluter Typen-Mischmasch. Da mal String und Char dort wieder std::wstring bzw. wchar_t. An anderer Stelle wieder const wchar_t* wegen Win32-API. Wenn ich sowieso eine Char/String Klasse brauche nehme ich auch die.
Und warum verwendest du dann nicht einfach überall wstring?
-
Dafür hat jede Klasse natürlich ihr eigenes Type-Object damit man feststellen kann ob die Typen gleich sind. Natürlich haben meine Klassen auch virtuelle Funktionen z.B. die um das Type-Object zurückzugeben.
Glaubt mir wenn es anders ginge würde ich es auch anders machen.
-
Streamer schrieb:
Dafür hat jede Klasse natürlich ihr eigenes Type-Object damit man feststellen kann ob die Typen gleich sind. Natürlich haben meine Klassen auch virtuelle Funktionen z.B. die um das Type-Object zurückzugeben.
Also eine handgebaute Version von RTTI - viel Spaß damit

PS: Im Bezug auf deine Char-Klasse - dir ist hoffentlich klar, daß so ein Char mit den virtuellen Methoden deutlich größer wird als der darunter gekapselte wchar_t.
-
Streamer schrieb:
Dafür hat jede Klasse natürlich ihr eigenes Type-Object damit man feststellen kann ob die Typen gleich sind. Natürlich haben meine Klassen auch virtuelle Funktionen z.B. die um das Type-Object zurückzugeben.
Okay, noch schlimmer. Nicht nur dass dir
typeiddie Arbeit abnehmen könnte, eindeutige Typ-IDs zu haben, sondern dass das immer auf eine explizite Fallunterscheidung auf User-Seite hinausläuft. Das ist genau der Grund, wieso es virtuelle Funktionen gibt.Streamer schrieb:
Glaubt mir wenn es anders ginge würde ich es auch anders machen.
Ich erlebe es selbst oft genug, dass mir irgendein Ansatz nicht sofort einfällt, aber meist gibts eben schon eine bessere Lösung. Und oft ist diese gar nicht mal so kompliziert

Warum kannst du keine virtuellen Funktionen verwenden, sodass der Aufrufcode polymorph und ohne Fallunterscheidung bleibt?
-
Also ich zögere ja schon seit einer Seite zu fragen, aber irgendwie dämmerts mir jetzt dass das hier wirklich Ernst ist. Also sagt mal: Gehts hier grad wirklich darum strings als Vektoren aus Zeichenobjekten die virtuelle Methoden haben und von Basisklassen erben abzubilden? WTF? Sowas trauen sich doch noch nichtmal Java-Anhänger
