Nehmen wir an, ich habe oder werde eine Reihe verwandter Funktionen schreiben. Nehmen wir an, sie haben mit Mathematik zu tun. Organisatorisch sollte ich:
- Schreiben Sie diese Funktionen und fügen Sie sie in meinen
MyMath
Namespace ein und verweisen Sie über aufMyMath::XYZ()
- Erstellen Sie eine Klasse mit dem Namen
MyMath
und machen Sie diese Methoden statisch und verweisen Sie auf ähnlicheMyMath::XYZ()
Warum sollte ich eine über die andere wählen, um meine Software zu organisieren?
c++
namespaces
static-methods
RobertL
quelle
quelle
Antworten:
Verwenden Sie standardmäßig Namespace-Funktionen.
Klassen sollen Objekte erstellen und keine Namespaces ersetzen.
Im objektorientierten Code
Scott Meyers hat einen ganzen Artikel für sein effektives C ++ - Buch zu diesem Thema geschrieben: "Bevorzugen Sie Nicht-Mitglieder-Nicht-Freund-Funktionen gegenüber Mitgliedsfunktionen". Ich habe einen Online-Verweis auf dieses Prinzip in einem Artikel von Herb Sutter gefunden:http://www.gotw.ca/gotw/084.htm
Das Wichtigste ist: In C ++ gehören Funktionen im selben Namespace wie eine Klasse zur Schnittstelle dieser Klasse (da ADL diese Funktionen beim Auflösen von Funktionsaufrufen durchsucht).
Namespace-Funktionen haben, sofern sie nicht als "Freund" deklariert sind, keinen Zugriff auf die Interna der Klasse, während statische Methoden dies tun.
Dies bedeutet zum Beispiel, dass Sie bei der Pflege Ihrer Klasse, wenn Sie die Interna Ihrer Klasse ändern müssen, in allen Methoden, einschließlich der statischen, nach Nebenwirkungen suchen müssen.
Erweiterung I.
Hinzufügen von Code zu einer Klassenschnittstelle.
In C # können Sie einer Klasse Methoden hinzufügen, auch wenn Sie keinen Zugriff darauf haben. In C ++ ist dies jedoch unmöglich.
Aber immer noch in C ++ können Sie eine Namespace-Funktion hinzufügen, selbst zu einer Klasse, die jemand für Sie geschrieben hat.
Auf der anderen Seite ist dies beim Entwerfen Ihres Codes wichtig, da Sie Ihre Benutzer durch Platzieren Ihrer Funktionen in einem Namespace dazu berechtigen, die Benutzeroberfläche der Klasse zu erweitern / zu vervollständigen.
Erweiterung II
Als Nebeneffekt des vorherigen Punktes ist es unmöglich, statische Methoden in mehreren Headern zu deklarieren. Jede Methode muss in derselben Klasse deklariert sein.
Für Namespaces können Funktionen aus demselben Namespace in mehreren Headern deklariert werden (die fast standardmäßige Swap-Funktion ist das beste Beispiel dafür).
Erweiterung III
Die grundlegende Coolness eines Namespace besteht darin, dass Sie es in einigen Codes vermeiden können, ihn zu erwähnen, wenn Sie das Schlüsselwort "using" verwenden:
Und Sie können die "Verschmutzung" sogar auf eine Klasse beschränken:
Dieses "Muster" ist für die ordnungsgemäße Verwendung der fast standardmäßigen Swap-Sprache obligatorisch.
Und dies ist mit statischen Methoden in Klassen unmöglich.
C ++ - Namespaces haben also ihre eigene Semantik.
Es geht aber noch weiter, da Sie Namespaces ähnlich wie bei der Vererbung kombinieren können.
Wenn Sie beispielsweise einen Namespace A mit einer Funktion AAA und einen Namespace B mit einer Funktion BBB haben, können Sie einen Namespace C deklarieren und AAA und BBB mit dem Schlüsselwort using in diesen Namespace bringen.
Fazit
Namespaces stehen für Namespaces. Klassen sind für Klassen.
C ++ wurde so konzipiert, dass jedes Konzept anders ist und in unterschiedlichen Fällen unterschiedlich verwendet wird, um unterschiedliche Probleme zu lösen.
Verwenden Sie keine Klassen, wenn Sie Namespaces benötigen.
Und in Ihrem Fall benötigen Sie Namespaces.
quelle
Es gibt viele Leute, die mir nicht zustimmen würden, aber so sehe ich das:
Eine Klasse ist im Wesentlichen eine Definition einer bestimmten Art von Objekt. Statische Methoden sollten Operationen definieren, die eng mit dieser Objektdefinition verbunden sind.
Wenn Sie nur eine Gruppe verwandter Funktionen haben, die keinem zugrunde liegenden Objekt oder einer Definition einer Objektart zugeordnet sind , würde ich sagen, dass Sie nur einen Namespace verwenden. Nur für mich ist dies konzeptionell viel sinnvoller.
Fragen Sie sich in Ihrem Fall beispielsweise: "Was ist ein MyMath?" Wenn
MyMath
keine Art von Objekt definiert wird, würde ich sagen: Machen Sie es nicht zu einer Klasse.Aber wie gesagt, ich weiß, dass es viele Leute gibt, die mir (sogar vehement) nicht zustimmen würden (insbesondere Java- und C # -Entwickler).
quelle
typedef
Verwenden Sie andernfalls Namespace-Funktionen.
Antwort auf die Kommentare: Ja, statische Methoden und statische Daten werden häufig überbeansprucht. Aus diesem Grund habe ich nur zwei verwandte Szenarien angeboten, in denen ich denke, dass sie hilfreich sein können. Wenn er im spezifischen Beispiel des OP (eine Reihe von mathematischen Routinen) die Möglichkeit haben möchte, Parameter anzugeben - beispielsweise einen Kerndatentyp und eine Ausgabegenauigkeit -, die auf alle Routinen angewendet werden, könnte er Folgendes tun:
Wenn Sie das nicht brauchen, verwenden Sie auf jeden Fall einen Namespace.
quelle
template
Argumente zu vermeiden !Sie sollten einen Namespace verwenden, da ein Namespace gegenüber einer Klasse viele Vorteile bietet:
using
Klassenmitglied sein; Sie könnenusing
ein Namespace-Mitgliedusing class
,using namespace
ist aber nicht allzu oft eine gute IdeeStatische Mitglieder werden meiner Meinung nach sehr, sehr überbeansprucht. Sie sind in den meisten Fällen keine wirkliche Notwendigkeit. Statische Elementfunktionen sind wahrscheinlich besser als Funktionen für den Dateibereich geeignet, und statische Datenelemente sind nur globale Objekte mit einem besseren, unverdienten Ruf.
quelle
inline
Schlüsselwort, um ODR zu erfüllen.inline
, und es wird NICHT der Körper einer Funktion "inliniert". Der eigentliche (und durch den Standard garantierte) Zweck voninline
besteht darin, mehrere Definitionen zu verhindern. Lesen Sie mehr über "One Definition Rule" für C ++. Außerdem wurde die verknüpfte SO-Frage aufgrund vorkompilierter Header-Probleme anstelle von ODR-Problemen nicht kompiliert.Ich würde Namespaces bevorzugen, auf diese Weise können Sie private Daten in einem anonymen Namespace in der Implementierungsdatei haben (damit sie im Gegensatz zu
private
Mitgliedern überhaupt nicht im Header angezeigt werden müssen). Ein weiterer Vorteil ist, dassusing
die Clients der Methoden durch Ihren Namespace die Angabe deaktivieren könnenMyMath::
quelle
Ein weiterer Grund für die Verwendung von class - Option zur Verwendung von Zugriffsspezifizierern. Sie können dann möglicherweise Ihre öffentliche statische Methode in kleinere private Methoden aufteilen. Öffentliche Methoden können mehrere private Methoden aufrufen.
quelle
private
Methoden sind zugänglicher als eine Methode, deren Prototyp überhaupt nicht in einem Header veröffentlicht wird (und daher unsichtbar bleibt). Ich erwähne nicht einmal die bessere Kapselung, die anonym benannte Funktionen bieten..cpp
Datei ausblenden, wodurch sie für diese Übersetzungseinheit privat werden, ohne dass jemand, der die Header-Datei liest, überflüssige Informationen erhält. Tatsächlich versuche ich, mich für die PIMPL-Sprache einzusetzen..cpp
Datei einfügen, wenn Sie Vorlagen verwenden möchten.Sowohl der Namespace als auch die Klassenmethode haben ihre Verwendung. Namespace kann auf mehrere Dateien verteilt werden. Dies ist jedoch eine Schwachstelle, wenn Sie den gesamten zugehörigen Code erzwingen müssen, um in eine Datei zu gelangen. Wie oben erwähnt, können Sie mit der Klasse auch private statische Mitglieder in der Klasse erstellen. Sie können es im anonymen Namespace der Implementierungsdatei haben, es ist jedoch immer noch ein größerer Bereich als sie in der Klasse zu haben.
quelle
private:
solche. und in vielen Fällen, in denen ein privilegierter Zugriff erforderlich zu sein scheint , kann dies herausgerechnet werden. Die "privateste" Funktion ist eine, die nicht in einem Header erscheint.private:
Methoden können diesen Vorteil niemals genießen.