Standardmäßig werden Funktionen mit Namensraum verwendet.
Klassen sind dazu da, Objekte zu erstellen, nicht um Namensräume zu ersetzen.
In objektorientiertem Code
Scott Meyers hat für sein Buch Effective C++ einen ganzen Artikel zu diesem Thema geschrieben, "Prefer non-member non-friend functions to member functions". Ich fand einen Online-Verweis auf dieses Prinzip in einem Artikel von Herb Sutter: http://www.gotw.ca/gotw/084.htm
Das ist wichtig zu wissen: In C++ gehören Funktionen, die sich im gleichen Namensraum wie eine Klasse befinden und die diese Klasse als Parameter haben, zur Schnittstelle dieser Klasse (weil ADL sucht diese Funktionen bei der Auflösung von Funktionsaufrufen).
Zum Beispiel:
- Nehmen wir an, Sie haben einen Namespace N
- Nehmen wir an, Sie haben eine Klasse C , deklariert im Namensraum N ( mit anderen Worten, sein vollständiger Name lautet N::C )
- Nehmen wir an, Sie haben eine Funktion F , deklariert im Namensraum N ( mit anderen Worten, sein vollständiger Name lautet N::F )
- Nehmen wir an, die Funktion F hat unter seinen Parametern auch einen Parameter vom Typ C
... Dann N::F ist Teil von N::C öffentlichen Schnittstelle.
Namespaced-Funktionen haben, sofern sie nicht als "friend" deklariert sind, keinen Zugriff auf die Interna der Klasse, während statische Methoden das Recht haben, auf die Interna der Klasse zuzugreifen.
Das bedeutet zum Beispiel, dass Sie bei der Wartung Ihrer Klasse, wenn Sie die Interna Ihrer Klasse ändern müssen, nach Seiteneffekten in allen Methoden, einschließlich der statischen, suchen müssen.
Erweiterung I
Hinzufügen von Code zur Schnittstelle einer Klasse.
In C# können Sie einer Klasse auch dann Methoden hinzufügen, wenn Sie keinen Zugriff auf die Klasse haben. In C++ ist dies jedoch unmöglich.
Aber auch in C++ können Sie eine Funktion mit Namensraum hinzufügen, sogar zu einer Klasse, die jemand für Sie geschrieben hat.
Von der anderen Seite aus gesehen, ist dies wichtig, wenn Sie Ihren Code entwerfen, denn indem Sie Ihre Funktionen in einen Namensraum stellen, erlauben Sie Ihren Benutzern, die Schnittstelle der Klasse zu erweitern/vervollständigen.
Erweiterung II
Ein Nebeneffekt des vorherigen Punktes ist, dass es unmöglich ist, statische Methoden in mehreren Headern zu deklarieren. Jede Methode muss in derselben Klasse deklariert werden.
Bei 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
Das Schöne an einem Namespace ist, dass man ihn in manchem Code nicht erwähnen muss, wenn man das Schlüsselwort using
:
#include <string>
#include <vector>
// Etc.
{
using namespace std ;
// Now, everything from std is accessible without qualification
string s ; // Ok
vector v ; // Ok
}
string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR
Und Sie können die "Verschmutzung" sogar auf eine Klasse beschränken:
#include <string>
#include <vector>
{
using std::string ;
string s ; // Ok
vector v ; // COMPILATION ERROR
}
string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR
Dieses "Muster" ist obligatorisch für die korrekte Verwendung der nahezu standardisierten Swap-Sprache.
Und das ist mit statischen Methoden in Klassen nicht möglich.
C++-Namensräume haben also ihre eigene Semantik.
Aber es geht noch weiter, denn Sie können Namensräume ähnlich wie bei der Vererbung kombinieren.
Wenn Sie zum Beispiel einen Namespace haben A
mit einer Funktion AAA
einen Namensraum B
mit einer Funktion BBB
können Sie einen Namespace deklarieren C
und bringen AAA
y BBB
in diesem Namespace mit dem Schlüsselwort using
.
Sie können sogar den gesamten Inhalt eines Namespaces in einen anderen bringen, mit using namespace
wie mit dem Namensraum D gezeigt!
namespace A
{
void AAA();
void AAA2();
}
namespace B
{
void BBB();
}
namespace C
{
using A::AAA;
using B::BBB;
}
namespace D
{
using namespace A;
using namespace B;
}
void foo()
{
C::AAA();
// C::AAA2(); // ERROR, won't compile
C::BBB();
}
void bar()
{
D::AAA();
D::AAA2();
D::BBB();
}
Schlussfolgerung
Namespaces sind für Namespaces. Klassen sind für Klassen.
C++ wurde so konzipiert, dass jedes Konzept anders ist und in unterschiedlichen Fällen als Lösung für unterschiedliche Probleme verwendet wird.
Verwenden Sie keine Klassen, wenn Sie Namespaces benötigen.
Und in Ihrem Fall brauchen Sie Namespaces.