Von std::string erben
-
Mahlzeit;
Idee ist, zum Bau einersplit
Methode vonstd::string
zu erben. Bisher habe ichclass mystring : public string{ private: string origin; public: mystring(const string &str) : string(str){ origin = str; }; void split(const char delimiter){ for( size_t cpos = 0; cpos < origin.length(); cpos++){ size_t fpos = origin.find(delimiter, cpos); string chunk = origin.substr(cpos, fpos - cpos); cpos += chunk.length() + 1; cout << chunk << endl; } }; };
und meine Frage ist, was es da noch so zu beachten gibt. Der Return-Value ist noch nicht näher festgelegt.
MFG
-
@_ro_ro Warum willst du von
std::string
erben? Warum nicht einfach eine freie Funktion, die das für dich macht? Oder, wenn es eine Klasse sein soll, warum nicht eine Klasse die einfach einenstd::string
als Member hat.
Was mich auch zu der Frage bringt: Warum erbst du vonstd::string
und hast einenstd::string
Member?P.S.
std::string
hat keinen virtuellen Destruktor, das birgt also die Gefahr, dassmystring
nicht richtig freigegeben wird, wenn du nur irgendwo einen Pointer auf die Base Klasse speicherst und darüber deinenmystring
freigeben möchtest. (Ich meine, das wäre dann undefined behaviour).
-
@Schlangenmensch sagte in Von std::string erben:
@_ro_ro Warum willst du von
std::string
erben?Weil ich was lernen will.
Was mich auch zu der Frage bringt: Warum erbst du von
std::string
und hast einenstd::string
Member?Genau diese Frage hat mich auch beschäftigt. Und so habe ich darüber nachgedacht und bin zu dem Schluss gekommen, daß ich diesen Member gar nicht brauche, denn das Original steckt ja in
std::string origin = *this;
.Danke für Deine Hinweise!!!
MFG
PS: Der Destruktor meiner
mystring
Class wird aufgerufen, das habe ich geprüft.
-
@_ro_ro Wenn du was lernen möchtest, solltest du lernen, nicht von Klassen zu erben, die keinen virtuellen Destruktor haben.
std::string* base = new mystring("It's a string"); delete base;
Mit einem virtuellen Destruktor würde der Destruktor von mystring aufgerufen, ohne hast du keine Chance über den Pointer auf die Basisklasse dein Objekt aufzuräumen.
-
bisher habe ich gelernt,
new
nicht zu verwenden. Und was ist jetzt ein virtueller Destruktor?MFG
-
-
Man erbt nicht von den std::-Klassen. Siehe u.a. https://quuxplusone.github.io/blog/2018/12/11/dont-inherit-from-std-types/
-
Manchmal muss man eben Objekte im Freispeicher erzeugen. Ob das mit
new
oderstd::make_unique
geschieht, ist zwar für das Freigeben relevant, aber nicht für diese Fragestellung. Das Problem existiert also auch, ohne dass du explizit new rufst.
-
-
-
@_ro_ro Ein virtueller Destruktor ist ein Desturkor, mit dem Keyword
virtual
. Virtuelle Funktionen generell überschreiben die Funktion des Basisklasse, auch wenn die über einen Pointer auf die Basisklasse aufgerufen werden.using namespace std; class base { public: virtual ~base() = default; virtual void output() { cout << " base\n"; } }; class inhereited : public base { public: void output() override { cout << "inherited\n"; } }; int main(int, char const**) { base* base = new inhereited(); base->output(); delete base; return 0; }
Im Falle eines Destruktors gilt im Prinzip dasselbe, nur das sicher gestellt wird, das auch die Base aufgeräumt wird.
Das
new
verwende ich nur um schnell ein Beispiel zu haben, in realem Code wäre das ein Smartpointer, was aber am Problem nichts ändert.
-
-
-
@_ro_ro Rentner-Cop?
Bei Vererbung macht man sich unter anderem die Eigenschaft zu nutze, dass man den internen Zustand des "Elternobjekts" in der abgeleiteten Klasse ändern darf...
-
@nameName sagte in Von std::string erben:
@_ro_ro Rentner-Cop?
Bei Vererbung macht man sich unter anderem die Eigenschaft zu nutze, dass man den internen Zustand des "Elternobjekts" in der abgeleiteten Klasse ändern darf...
Bei Vererbung wird kein Elternobjekt erstellt sondern eine Instanz der erbenden Klasse.
MFG
-
@_ro_ro sagte in Von std::string erben:
@nameName sagte in Von std::string erben:
@_ro_ro Rentner-Cop?
Bei Vererbung macht man sich unter anderem die Eigenschaft zu nutze, dass man den internen Zustand des "Elternobjekts" in der abgeleiteten Klasse ändern darf...
Bei Vererbung wird kein Elternobjekt erstellt sondern eine Instanz der erbenden Klasse.
MFG
Ähm... nein. Beim Erstellen des konkreten Objekts werden von alle geerbten Klassen Instanzen erstellt, sie sind halt nur Teil des konkreten Objekts.
-
@DocShoe sagte in Von std::string erben:
@_ro_ro sagte in Von std::string erben:
@nameName sagte in Von std::string erben:
@_ro_ro Rentner-Cop?
Bei Vererbung macht man sich unter anderem die Eigenschaft zu nutze, dass man den internen Zustand des "Elternobjekts" in der abgeleiteten Klasse ändern darf...
Bei Vererbung wird kein Elternobjekt erstellt sondern eine Instanz der erbenden Klasse.
MFG
Ähm... nein. Beim Erstellen des konkreten Objekts werden von alle geerbten Klassen Instanzen erstellt, sie sind halt nur Teil des konkreten Objekts.
Nur Wenn der Elternkonstruktor aufgerufen wurde oder ist das grundsätzlich so?
MFG
-
@_ro_ro
Grundsätzlich und immer. Der Konstruktor wird immer benötigt, um alle Member einer Klasse zu initialisieren (selbst wenn sie default-constructed sind). Wenn du den Konstruktor einer Basisklasse nicht explizit selbst aufrufst ( durch die : Notation) erzeugt der Compiler einen impliziten Konstruktoraufruf des jeweiligen Defaultkonstruktors (ohne Parameter).Edit:
Ab C++11 kann man die Member direkt in der Deklaration der Klasse initialisieren, das musste man früher im Konstruktor machen. Wenn dann die Konstruktor ender jeweiligen Basisklassen nicht aufgerufen würde, wären die Member höchstens Default-konstruiert, aber nicht mit den Werten, mit denen sie im Konstruktor initialisiert werden.
-
danke Dir!! Eigentlich logisch, denn der Destruktor der Elternklasse(n) wird ja immer aufgerufen.
MFG
-
Nicht zwingend. Mann kann auch Käse programmieren, nehmen wir mal dein Anliegen und benutzen das absichtlich falsch:
#include <string> #include <memory> class MyString : public std::string { // hier liegt iwas auf dem Heap, das explizit aufgeräumt werden muss. public: MyString() = default; }; int main() { // unique_ptr hält einen Zeiger auf die Basisklasse! std::unique_ptr<std::string> = std::make_unique<MyString>(); }
Führt zu einem Problem, weil der Destruktor von
MyString
nicht aufgerufen wird. Das liegt daran, dass der Destruktor vonstd::string
nichtvirtual
ist und daher den Destruktor der Elternklasse nicht aufruft.
Deswegen sollte man auch nicht von Klassen erben, die keinen virtuellen Destruktor haben.Und wo wir bei dem Ursprungsproblem sind:
Wirf mal einen Blick auf boost Tokenizer. Die boost-Bibliotheken sind frei und für fast jeden C++ Compiler verfügbar. Die Installation kann etwas umständlich sein, wenn man sie selbst bauen muss, weil es keine Prebuilt Distro für deinen Compiler gibt.
-
...oder auf sowas wie https://abseil.io/docs/cpp/guides/strings#abslstrsplit-for-splitting-strings
Boost ist zwar schön, ich finde es aber oft recht kompliziert zu benutzen (nicht, dass abseil nicht auch seine eigenen Probleme hätte...)
-
Wie lange darf der Troll @_ro_ro hier noch posten?
-
Vererbung ist nicht immer sinnvoll. Erfahrungsgemäß ist Vererbung genau dann zweckmäßig, wenn Objekte um bestimmte Methoden erweitert werden oder gegebene Methoden spezialisiert werden sollen wobei die geerbten Methoden natürlich auch verwendet werden.
Insofern ist die Idee, das
std::string
Objekt um eine Methodesplit
zu erweitern alles Andere als abwegig. Zumal 1. das Splitten ohnehin nur auf Strings angewendet wird und 2. sehr oft benötigt wird. Genau das ist der Sinn einer objektorientierten Programmierung.Viele Grüße!
PS: Meine Splitfunktion (classless) funktioniert einwandfrei. Auch mit UTF-8-kodierten Zeichenketten.