Frage

diese Klassen in Betracht.

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

Diese Funktion

void BaseFoo( std::vector<Base*>vec )
{
    ...
}

Und schließlich mein Vektor

std::vector<Derived*>derived;

Ich möchte derived passieren BaseFoo funktionieren, aber der Compiler lässt mich nicht. Wie kann ich dieses Problem lösen, ohne den gesamten Vektor zu einem std::vector<Base*> zu Kopieren?

War es hilfreich?

Lösung

vector<Base*> und vector<Derived*> sind unabhängige Typen, so dass Sie dies nicht tun. Dies erklärt sich in der C ++ FAQ hier .

Sie benötigen eine Variable von einem vector<Derived*> zu einem vector<Base*> ändern und Derived Objekte hinein eingefügt werden.

Auch, um zu verhindern das Kopieren des vector unnötig, sollten Sie es von const-Verweise übergeben, nicht von Wert:

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

Schließlich, um Speicherlecks zu vermeiden, und der Code exception-sicher machen, sollten Sie einen Behälter mit entworfen Heap zugewiesenen Objekte zu handhaben, z:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

Alternativ können Sie den Vektor ändern, um einen intelligenten Zeiger anstelle der Verwendung von rohen Zeigern zu halten:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

oder

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

In jedem Fall müßten Sie Ihre BaseFoo Funktion entsprechend ändern.

Andere Tipps

Anstatt das Container-Objekt (vector<>) zu bestehen, übergeben Sie in begin und end Iteratoren wie der Rest der STL-Algorithmen. Die Funktion, die sie empfängt, wird als Templat, und es wird keine Rolle, ob Sie in Abgeleitet passieren * oder Basis *.

Dieses Problem tritt in Programmiersprachen, die wandelbar Behälter haben. Sie können keine wandelbare Tüte Äpfel als Beutel von Obst herumreichen, weil man nicht sicher sein kann, dass jemand anderes nicht eine Zitrone in die Tasche von Obst nicht gestellt, wonach sie nicht mehr als eine Tüte Äpfel qualifiziert. Wenn der Sack Äpfel, die nicht wandelbar waren, vorbei es sich um, als eine Tüte mit Obst wäre schön. Suchen Sie nach Kovarianz / Kontra.

ist eine Option, um eine Vorlage zu verwenden,

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

Der Nachteil ist, dass die Umsetzung im Header zu sein hat, und Sie werden ein wenig Code aufblasen zu bekommen. Sie werden sich mit verschiedenen Funktionen wickeln für jeden Typ instanziiert wird, aber der Code bleibt gleich. Je nach Anwendungsfall ist es eine schnelle und schmutzige Lösung.

Bearbeiten, sollte ich den Grund stellen wir eine Vorlage hier brauchen, weil wir von mehreren anderen Plakaten wie erwähnt versuchen, den gleichen Code für nicht verwandte Arten zu schreiben. Vorlagen können Sie genau diese Probleme lösen. Ich aktualisiert es auch eine konstante Referenz zu verwenden. Sie sollten auch „schwere“ Objekte wie ein Vektor durch konstante Referenz geben, wenn Sie nicht über eine Kopie benötigen, die im Grunde immer ist.

Im Allgemeinen würden Sie mit einem Behälter von Basiszeigern starten, nicht andersrum.

Unter Matt Price Antwort von oben, da Sie im Voraus wissen, welche Arten Sie mit Ihrer Funktion verwenden möchten, können Sie die Funktion Vorlage in der Header-Datei deklarieren und dann explizite instantiations für diese Typen hinzufügen:

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );

Wenn Sie mit einer Drittanbieter-Bibliothek zu tun, und dies ist Ihre einzige Hoffnung, dann können Sie dies tun:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

Ansonsten befestigen Sie Ihren Code mit einem der anderen suggesstions.

Wenn std::vector unterstützt, was Sie fordern, dann wäre es möglich, das C ++ Typ-System zu besiegen, ohne Casts mit (edit: ChrisN der Verbindung zu dem C ++ FAQ Lite spricht über die gleiche Ausgabe):

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

void pushStuff(std::vector<Base*>& vec) {
    vec.push_back(new Derived2);
    vec.push_back(new Base);
}

...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!

Da Ihr BaseFoo() Funktion den Vektor nach Wert annimmt, kann es nicht die ursprüngliche Vektor ändern, die Sie übergeben, so was ich geschrieben habe nicht möglich wäre. Aber wenn es eine nicht konstante Referenz nimmt und Sie reinterpret_cast<std::vector<Base*>&>() Ihre std::vector<Derived*> passieren, könnten Sie nicht das Ergebnis erhalten, die Sie wollen, und das Programm abstürzen.

Java-Arrays unterstützen covariant Subtypisierung, und dies erfordert Java Führt eine Überprüfung Laufzeittyp jedes Mal, wenn Sie einen Wert in einem Array speichern. Auch dies ist unerwünscht.

Sie sind nicht verwandten Arten - Sie können nicht.

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