Ich brauche einige C ++ - Guru-Meinungen über die Erweiterung von std :: string

7

Ich wollte schon immer etwas mehr Funktionalität in der STL-Zeichenkette haben. Da das Unterklassifizieren von STL-Typen ein Nein ist, habe ich meistens gesehen, dass die empfohlene Methode zur Erweiterung dieser Klassen nur darin besteht, Funktionen (nicht Elementfunktionen) zu schreiben, die den Typ als erstes Argument verwenden.

Ich war nie begeistert von dieser Lösung. Zum einen ist es nicht unbedingt offensichtlich, wo alle diese Methoden im Code sind, zum anderen mag ich die Syntax einfach nicht. Ich möchte benutzen . wenn ich Methoden anrufe!

Vor einer Weile habe ich Folgendes gefunden:

%Vor%

Beachten Sie, dass StringBox einen Verweis auf eine std :: string für die Konstruktion benötigt ... Dies setzt einige interessante Grenzen für ihre Verwendung (und ich hoffe, dass sie nicht zum Problem der Proliferation der String-Klasse beiträgt) ... Mein eigener Code, ich deklariere ihn fast immer auf dem Stack in einer Methode, nur um eine std :: string zu ändern.

Ein Anwendungsbeispiel könnte so aussehen:

%Vor%

Meine Frage ist: Was denken die C ++ - Gurus der StackOverflow-Community über diese Methode der STL-Erweiterung?

    
dicroce 10.01.2010, 17:27
quelle

7 Antworten

15

Da die meisten von uns "Gurus" die Verwendung von freien Funktionen bevorzugen, die wahrscheinlich in einem Namespace enthalten sind, kann ich mit Sicherheit sagen, dass Ihre Lösung nicht populär sein wird. Ich fürchte, ich kann keinen einzigen Vorteil sehen, den es hat, und die Tatsache, dass die Klasse eine Referenz enthält, ist eine Einladung dazu, dass sie zu einer unverbindlichen Referenz wird.

    
anon 10.01.2010, 17:35
quelle
19
  

Ich war nie begeistert von dieser Lösung. Zum einen ist es nicht unbedingt offensichtlich, wo alle diese Methoden im Code sind, zum anderen mag ich die Syntax einfach nicht. Ich möchte benutzen . wenn ich Methoden anrufe!

Und ich möchte $!---& verwenden, wenn ich Methoden anrufe! Komm damit klar. Wenn Sie C ++ - Code schreiben, halten Sie sich an C ++ - Konventionen. Und eine sehr wichtige C ++ - Konvention ist, wenn möglich, Nicht-Member-Funktionen zu bevorzugen.

Es gibt einen Grund, warum C ++ - Gurus dies empfehlen:

Es verbessert die Kapselung, Erweiterbarkeit und Wiederverwendung. ( std::sort kann mit allen Iteratorpaaren arbeiten , weil kein Mitglied eines einzelnen Iterators oder einer Containerklasse ist. Und egal, wie Sie std::string erweitern, Sie können nicht brechen Sie es, solange Sie sich an Nicht-Member-Funktionen halten, und selbst wenn Sie keinen Zugriff auf den Quellcode einer Klasse haben oder dies nicht ändern dürfen, können Sie ihn dennoch erweitern, indem Sie Nicht-Member definieren Funktionen)

Ich persönlich kann den Punkt in Ihrem Code nicht sehen. Ist das nicht viel einfacher, lesbarer und kürzer?

%Vor%

Wenn Sie in Rom sind, tun Sie es wie die Römer, wie das Sprichwort sagt. Besonders wenn die Römer gute Gründe haben, so zu handeln wie sie. Und vor allem, wenn Ihre eigene Art, es zu tun, nicht wirklich einen Vorteil hat. Es ist fehleranfälliger, verwirrend für Leute, die Ihren Code lesen, nicht-idiomatisch und es sind nur mehr Codezeilen, die dasselbe tun.

Was Ihr Problem angeht, dass es schwierig ist, die Nichtmitgliedsfunktionen zu finden, die string erweitern, legen Sie sie in einen Namespace, wenn das ein Problem ist. Dafür sind sie da. Erstelle ein namespace StringUtil oder etwas und lege sie dort hin.

    
jalf 10.01.2010 17:38
quelle
2

Ich füge etwas hinzu, das noch nicht veröffentlicht wurde. Die Boost-String-Algorithmen-Bibliothek hat den Ansatz der freien Template-Funktion und die Zeichenkette verwendet Algorithmen, die sie bereitstellen, sind spektakulär wiederverwendbar für alles, was wie eine Zeichenkette aussieht: std :: string, char *, std :: vector, Iterator-Paare ... Sie nennen es! Und sie fügen sie alle ordentlich in den boost :: -Algorithmus-Namespace ein (ich benutze oft using namespace algo = boost::algorithm , um den String-Manipulations-Code kürzer zu machen).

Überlegen Sie sich also, wie Sie freie Template-Funktionen für Ihre String-Erweiterungen verwenden können, und schauen Sie sich Boost String Algorithms an, wie Sie sie "universal" machen können.

Für eine sichere Druckformat-Formatierung lesen Sie Boost.Format . Es kann in Strings und Streams ausgegeben werden.

Ich wollte auch, dass alles eine Mitgliedsfunktion ist, aber ich beginne jetzt, das Licht zu sehen. UML und Doxygen drängen mich immer, Funktionen innerhalb von Klassen zu platzieren, weil ich von der Idee, dass C ++ API == Klassenhierarchie war, einer Gehirnwäsche unterzogen wurde.

    
Emile Cormier 10.01.2010 19:13
quelle
1

Wenn der Umfang der Zeichenfolge nicht mit dem StringBox identisch ist, können Sie segfaults erhalten:

%Vor%

Vermeide zumindest das Kopieren von Objekten, indem du den Zuweisungsoperator deklarierst und ctor private kopierst:

%Vor%

EDIT: in Bezug auf API, um Überraschungen zu verhindern, würde ich das StringBox besitzen seine Kopie der Zeichenfolge. Ich kann über 2 Möglichkeiten nachdenken:

  1. Kopiere die Zeichenfolge in ein Member (keine Referenz), erhalte das Ergebnis später - auch als Kopie
  2. Greifen Sie auf Ihre Zeichenkette über einen intelligenten Smart-Zeiger wie std::tr1::shared_ptr oder boost:shared_ptr zu, um ein zusätzliches Kopieren zu verhindern.
orip 10.01.2010 17:35
quelle
1

Das Problem mit losen Funktionen ist, dass sie lose Funktionen sind.

Ich wette, dass die meisten von Ihnen eine Funktion erstellt haben, die bereits von der STL bereitgestellt wurde, weil Sie einfach nicht wussten, dass die STL-Funktion existierte oder dass sie das tun konnte, was Sie erreichen wollten.

Es ist ein ziemlich strafendes Design, besonders für neue Benutzer. (Die STL bekommt auch neue Zusätze, die das Problem noch vergrößern.)

Google: C ++ zu string

Wie viele Ergebnisse erwähnen: std :: to_string

Ich bin genauso wahrscheinlich, eine alte C-Methode oder eine selbstgemachte Version zu finden, da ich die STL-Version einer bestimmten Funktion finden kann.

Ich bevorzuge die Methoden von Mitgliedern, weil Sie nicht lange suchen müssen, um sie zu finden, und Sie müssen sich keine Sorgen darüber machen, alte veraltete Versionen usw. zu finden. (also string.SomeMethod, ist ziemlich sicher die Methode, die Sie verwenden sollten, und es gibt Ihnen etwas Konkretes für Google.)

C # Stil Erweiterung Methoden wäre eine gute Lösung.

  1. Sie sind lose Funktionen.
  2. Sie erscheinen als Mitgliederfunktionen über IntelliSense.

Dies sollte jedem genau das ermöglichen, was er will.

Es scheint so, als könnte es in der IDE selbst durchgeführt werden, anstatt irgendwelche Sprachänderungen zu erfordern.

Wenn der Interpreter einen Aufruf an ein nicht vorhandenes Element aufruft, kann er im Prinzip Header auf passende loose Funktionen prüfen und sie dynamisch reparieren, bevor er sie an den Compiler weitergibt.

Ähnliches könnte gemacht werden, wenn die IntelliSense-Daten geladen werden.

Ich habe keine Ahnung, wie das für bestehende Funktionen funktionieren könnte, keine massive Änderung wie diese sollte auf die leichte Schulter genommen werden, aber für neue Funktionen, die eine neue Syntax verwenden, sollte es kein Problem sein.

%Vor%

Das kann für sich selbst oder als Mitglied von std :: string verwendet werden, und die IDE kann all das Grunzen verarbeiten.

Natürlich bleibt dabei das Problem, dass Methoden über verschiedene Header verteilt werden, was auf verschiedene Arten gelöst werden kann.

  1. Eine Art von extension header: string_ext, die allgemeine Methoden enthalten kann.
  2. Hmm ....

Das ist ein schwieriger zu lösendes Problem, ohne Probleme zu verursachen ...

    
Smoke 17.11.2012 02:34
quelle
0

Wenn Sie die verfügbaren Methoden erweitern möchten, um auf eine Zeichenfolge zu reagieren, würde ich sie erweitern, indem Sie eine Klasse mit statischen Methoden erstellen, die die Standardzeichenfolge als Parameter verwenden. Auf diese Weise können die Benutzer Ihre Dienstprogramme verwenden, müssen aber nicht die Signaturen ihrer Funktionen ändern, um eine neue Klasse zu verwenden.

Dies unterbricht das objektorientierte Modell ein wenig, macht den Code jedoch sehr viel robuster - d. h. wenn Sie Ihre String-Klasse ändern, hat das weniger Einfluss auf anderen Code.

Befolgen Sie die empfohlenen Richtlinien, sie sind aus einem bestimmten Grund da:)

    
Larry Watanabe 10.01.2010 17:34
quelle
0

Der beste Weg ist die Nutzung freigestellter Templates. Die nächstbeste ist die private Vererbung struct extended_str : private string , die übrigens in C ++ 0x einfacher wird, wie Sie using Konstruktoren können. Private Vererbung ist zu viel Mühe und zu riskant, nur um einige Algorithmen hinzuzufügen. Was du tust, ist zu riskant für alles.

Sie haben gerade eine nichttriviale Datenstruktur eingeführt, um eine Änderung der Interpunktion des Codes zu erreichen. Sie müssen eine Box für jedes string manuell erstellen und zerstören, und Sie müssen Ihre Methoden immer noch von den nativen unterscheiden. Sie werden diese Konvention schnell satt haben.

    
Potatoswatter 10.01.2010 18:08
quelle

Tags und Links