Frage

Es sieht aus wie ich ein grundlegendes Missverständnis über C ++ hatte: <

Ich mag die polymorphe Containerlösung. Vielen Dank SO, zu bringen, dass meine Aufmerksamkeit:)


Wir haben also eine Notwendigkeit, ein relativ generisches Container-Typ-Objekt zu erstellen. Es passiert auch einige geschäftliche Logik zu kapseln. Wir müssen jedoch im Wesentlichen beliebige Daten in diesem Container speichern - von primitiven Datentypen bis hin zu komplexen Klassen

.

So würde man sofort auf die Idee einer Template-Klasse springen und mit ihm getan werden. Allerdings habe ich C ++ Polymorphismus bemerkt und Vorlagen nicht gut zusammen spielen. Ist, dass es eine komplexe Logik, die wir arbeiten gehen zu müssen, würde ich lieber bleiben nur entweder mit Vorlagen oder Polymorphismus, und nicht versuchen, C ++ zu bekämpfen, indem sie beides tun.

Schließlich, da ich einen tun will oder die andere, ich würde es vorziehen, Polymorphismus. Ich finde es viel einfache Einschränkungen darzustellen, wie „diese Behälter Vergleichbare Typen enthalten“ - a la java

.

Bringen Sie mich zu dem Thema Frage: Am abstrakteste, ich stelle mir vor, dass ich einen „Container“ rein virtuelle Schnittstelle, die etwas haben könnte ähnlich „push (void * data) und pop (void * data)“ hat ( für die Aufzeichnung, versuche ich, nicht wirklich um einen Stapel zu implementieren).

Allerdings kann ich nicht wirklich wie void * auf der obersten Ebene, nicht die Unterschrift erwähnen, wird jedes Mal, wenn ich auf die Art der Daten ein Betonbehälter mit kann eine Einschränkung hinzufügen ändern möge arbeiten.

Summieren: Wir haben relativ komplexe Behälter, die verschiedene Art und Weise haben Elemente abzurufen. Wir wollen in der Lage sein, die Einschränkungen für die Elemente zu variieren, die in die Behälter gehen kann. Elemente sollten mit mehreren Arten von Behältern arbeiten (so lange sie die Zwänge des jeweiligen Behälters erfüllen).

Edit: Ich sollte auch erwähnen, dass die Behälter selbst polymorph sein müssen. Das ist mein Hauptgrund für die nicht wollen, auf Vorlagen basierende C ++ verwenden.

So - soll ich meine Liebe für Java-Typen Schnittstellen fallen und mit Vorlagen gehen? Sollte ich void * und statisch alles werfen? Oder soll ich mit einer leeren Klassendefinition gehen „Element“, die nichts ausgeben und als meine Top-Level-Klasse in der „Elemente“ Hierarchie erklärt?

Einer der Gründe, warum ich Stack-Überlauf Liebe ist, dass viele der Antworten interessante Einblicke auf andere Ansätze bieten, die ich hatte nicht nicht einmal in Erwägung gezogen haben. Also vielen Dank im Voraus für Ihre Erkenntnisse und Kommentare.

War es hilfreich?

Lösung

Können Sie nicht ein Root-Container-Klasse haben, die Elemente enthält:

template <typename T>
class Container
{
public: 

   // You'll likely want to use shared_ptr<T> instead.
   virtual void push(T *element) = 0;
   virtual T *pop() = 0;
   virtual void InvokeSomeMethodOnAllItems() = 0;
};

template <typename T>
class List : public Container<T>
{
    iterator begin();
    iterator end();
public:
    virtual void push(T *element) {...}
    virtual T* pop() { ... }
    virtual void InvokeSomeMethodOnAllItems() 
    {
       for(iterator currItem = begin(); currItem != end(); ++currItem)
       {
           T* item = *currItem;
           item->SomeMethod();
       }
    }
};

Diese Container können dann um polymorph übergeben werden:

class Item
{
public:
   virtual void SomeMethod() = 0;
};

class ConcreteItem
{
public:
    virtual void SomeMethod() 
    {
        // Do something
    }
};  

void AddItemToContainer(Container<Item> &container, Item *item)
{
   container.push(item);
}

...

List<Item> listInstance;
AddItemToContainer(listInstance, new ConcreteItem());
listInstance.InvokeSomeMethodOnAllItems();

Das gibt Ihnen die Container-Schnittstelle in einer typsicheren generischen Art und Weise.

Wenn Sie auf die Art der Elemente Einschränkungen hinzufügen möchten, die enthalten sein können, können Sie etwas tun können:

class Item
{
public:
  virtual void SomeMethod() = 0;
  typedef int CanBeContainedInList;
};

template <typename T>
class List : public Container<T>
{
   typedef typename T::CanBeContainedInList ListGuard;
   // ... as before
};

Andere Tipps

Polymorphismus und Vorlagen tun spielen sehr gut zusammen, wenn man sie richtig verwendet werden.

Wie auch immer, ich verstehe, dass Sie nur eine Art von Objekten in jeder Container-Instanz gespeichert werden sollen. Wenn ja, verwenden Vorlagen. Dies wird verhindern, dass Sie den falschen Objekttyp versehentlich zu speichern.

Wie für Container-Schnittstellen: Je nach Design, vielleicht werden Sie in der Lage sein, sie auf Vorlagen zu machen, auch, und dann werden sie Methoden wie void push(T* new_element) haben. Denken Sie an, was Sie über das Objekt wissen, wann Sie es in einen Behälter (von einem unbekannten Typ) hinzufügen möchten. Wo wird das Objekt kommt aus in erster Linie? Eine Funktion, die void* zurückkehrt? Wissen Sie, dass es vergleichbar sein wird? Zumindest, wenn alle gespeicherten Objektklassen in Ihrem Code definiert sind, können Sie machen sie alle von einem gemeinsamen Vorfahren erben, sagen wir, Storable, und verwenden Sie Storable* statt void*.

Nun, wenn Sie sehen, dass Objekte werden immer durch ein Verfahren wie void push(Storable* new_element) in einen Behälter gegeben werden, dann wirklich wird es bei der Herstellung der Behälter eine Vorlage kein Mehrwert sein. Aber dann wissen Sie, es sollte Storables speichern.

Als erstes von allen, Vorlagen und Polymorphismus orthogonale Konzepte und sie gut zusammen spielen. Als nächstes warum wollen Sie eine bestimmte Datenstruktur? Was ist mit der STL oder Boost-Datenstrukturen (insbesondere Zeiger containter ) nicht für Sie arbeiten.

Bei Ihrer Frage, es klingt wie Sie die Vererbung in Ihrer Situation zu mißbrauchen würden. Es ist möglich, zu schaffen „ Einschränkungen “ auf, was geht in Ihren Containern, vor allem, wenn Sie mit Hilfe von Vorlagen. Diese Einschränkungen können über das hinausgehen, was Ihr Compiler und Linker wird dir geben. Es ist eigentlich mehr umständlich zu so etwas mit Vererbung und Fehler werden für die Laufzeit eher links.

Polymorphismus verwendet, sind Sie im Grunde mit einer Basisklasse für den Container verlassen und Klassen für die Datentypen abgeleitet. Die Basisklasse / abgeleiteten Klassen können beliebig viele virtuelle Funktionen haben, wie Sie benötigen, in beide Richtungen.

Natürlich würde dies bedeuten, dass Sie auch die primitiven Datentypen in abgeleiteten Klassen wickeln müssen. Wenn Sie die Verwendung von Vorlagen insgesamt überdenken würden, das ist, wo ich die Vorlagen verwenden würde. Machen Sie eine abgeleitete Klasse von der Basis, die eine Vorlage, und verwendet, die für die primitiven Datentypen (und andere, in denen Sie keine mehr Funktionalität benötigen, als durch die Vorlage zur Verfügung gestellt wird).

Vergessen Sie nicht, dass Sie Ihr Leben machen könnte einfacher durch typedefs für jeden der Templat-Typen -. Vor allem, wenn Sie später einer von ihnen in eine Klasse drehen müssen

Sie möchten vielleicht auch der Boost-Concept Check Library (BCCL) der entworfen, um Einschränkungen für die Template-Parameter von Templat-Klassen zur Verfügung zu stellen, Ihre Container in diesem Fall.

Und nur zu wiederholen, was andere gesagt hat, ich habe noch nie ein Problem Misch Polymorphismus und Vorlagen, und ich habe einige ziemlich komplexe Sachen mit ihnen gemacht.

Sie könnte nicht aufgeben Java-ähnliche Schnittstellen und auch Vorlagen verwenden. Josh Vorschlag eines generische Basisvorlage Container würden Sie geben sie sicherlich erlauben polymorph Container und ihre Kinder in der Nähe, sondern zusätzlich können Sie sicherlich Schnittstellen implementieren als abstrakte Klassen die darin enthaltenen Elemente zu sein. Es gibt keinen Grund, warum Sie könnte eine abstrakte IComparable Klasse nicht erstellen, wie Sie vorgeschlagen, so dass Sie eine polymorphe Funktion haben könnte wie folgt:

class Whatever
{
   void MyPolymorphicMethod(Container<IComparable*> &listOfComparables);
}

Dieses Verfahren kann nun jedes Kind von Containern nehmen, die jede Klasse enthält Umsetzung IComparable, so wäre es äußerst flexibel sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top