Ich habe eine Klasse, die std :: vector anpasst, um einen Container mit domänenspezifischen Objekten zu modellieren. Ich möchte dem Benutzer den größten Teil der std :: vector-API zur Verfügung stellen, damit er vertraute Methoden (Größe, Löschen, At usw.) und Standardalgorithmen für den Container verwenden kann. Dies scheint für mich ein wiederkehrendes Muster in meinen Entwürfen zu sein:
class MyContainer : public std::vector<MyObject>
{
public:
// Redeclare all container traits: value_type, iterator, etc...
// Domain-specific constructors
// (more useful to the user than std::vector ones...)
// Add a few domain-specific helper methods...
// Perhaps modify or hide a few methods (domain-related)
};
Ich bin mir der Praxis bewusst, Komposition gegenüber Vererbung zu bevorzugen, wenn eine Klasse für die Implementierung wiederverwendet wird - aber es muss eine Grenze geben! Wenn ich alles an std :: vector delegieren würde, gäbe es (nach meiner Zählung) 32 Weiterleitungsfunktionen!
Meine Fragen sind also ... Ist es in solchen Fällen wirklich so schlimm, die Implementierung zu erben? Was sind die Risiken? Gibt es eine sicherere Möglichkeit, dies zu implementieren, ohne so viel zu tippen? Bin ich ein Ketzer für die Verwendung der Implementierungsvererbung? :) :)
Bearbeiten:
Wie wäre es damit, klar zu machen, dass der Benutzer MyContainer nicht über einen std :: vector <> -Zeiger verwenden sollte:
// non_api_header_file.h
namespace detail
{
typedef std::vector<MyObject> MyObjectBase;
}
// api_header_file.h
class MyContainer : public detail::MyObjectBase
{
// ...
};
Die Boost-Bibliotheken scheinen dies die ganze Zeit zu tun.
Bearbeiten 2:
Einer der Vorschläge war die Verwendung freier Funktionen. Ich werde es hier als Pseudocode zeigen:
typedef std::vector<MyObject> MyCollection;
void specialCollectionInitializer(MyCollection& c, arguments...);
result specialCollectionFunction(const MyCollection& c);
etc...
Eine OO-Methode:
typedef std::vector<MyObject> MyCollection;
class MyCollectionWrapper
{
public:
// Constructor
MyCollectionWrapper(arguments...) {construct coll_}
// Access collection directly
MyCollection& collection() {return coll_;}
const MyCollection& collection() const {return coll_;}
// Special domain-related methods
result mySpecialMethod(arguments...);
private:
MyCollection coll_;
// Other domain-specific member variables used
// in conjunction with the collection.
}