4 Stimmen

C++ Vererbungsproblem

Hier sind meine Klassen:

ParentClass, ParentObj

DerivedClass (erbt von ParentClass), DerivedObj (erbt von ParentObj).

ParentClass hat ein geschütztes Mitglied:

std::vector< ParentObj* >

DerivedClass ordnet diesem Vektor nur DerivedObj*-Objekte zu.

Das Problem ist:

Wenn ich ParentClass verwende, möchte ich auf seine Vektorobjekte mit einem Iterator vom Typ zugreifen:

std::vector< ParentObj* >::const_iterator

Und wenn ich DerivedClass verwende, möchte ich auf seine Vektorobjekte mit einem Iterator vom Typ zugreifen:

std::vector< DerivedObj* >::const_iterator

Wie kann ich es zum Laufen bringen?

4voto

xtofl Punkte 39285

Sie können ein virtuelles Override in Ihrer DerivedClass Klasse, die einen Subtyp der ParentClass Typ zurückgeben...

struct ParentClass {
    virtual ParentObj* get( const size_t index ) {
       return m_objects[index];
    }
 };

 struct DerivedClass : public ParentClass {
    virtual DerivedObj* get( const size_t index ) {
       return dynamic_cast<DerivedObj*>( ParentClass::get(index) );
    }
 };

Beide Funktionen sind derselbe 'vtable'-Eintrag, obwohl ihr Rückgabetyp unterschiedlich ist.

Alternativ können Sie die gleiche Technik verwenden, um "geerbte" Iteratoren zu erstellen.

Darüber hinaus ist es keine schlechte Idee, einen Vektor von DerivedObj* in der DerivedClass Objekts, sofern Sie sicherstellen, dass sie auch in der ParentClass Vektor.

2voto

Matthieu M. Punkte 266317

Ich habe da eine Frage: Warum ist DerivedClass erbt von ParentClass ?

Benötigen Sie ein polymorphes Verhalten, oder möchten Sie die Implementierung von ParentClass ?

Die Vererbung wird oft missbräuchlich eingesetzt. Wirklich.

Dann gibt es das (typische) Problem, eine Containerklasse zu haben, und wie man ihre Elemente freilegt. Leider sind die Iteratoren (trotz all ihrer Vorzüge) im Gegensatz zu den Zeigern, die sie emulieren sollen, schlecht von der Sprache unterstützt.

Also, eine Erinnerung: Vererbung es un ist- Beziehung, für die Wiederverwendung von Code gibt es Zusammensetzung .

Hier könnte man perfekt eine Vorlagenklasse schreiben, die die Rolle des Containers übernimmt und gemeinsame Methoden bereitstellt.

Dann, für das Problem der Darstellung... können Sie Ihre eigenen Iteratoren schreiben, mit der korrekten von der Basis abgeleiteten Beziehung, oder Sie können sich dafür entscheiden, eine Anzahl von Algorithmen vorauszuwählen ( sort , foreach , erase_if ), die mit benutzerdefinierten Prädikaten funktionieren würde.

template <class Value>
class Container
{
public:
  template <class Pred>
  void sort(Pred iPred);

  template <class Pred>
  Pred foreach(Pred iPred); // maybe a const-version ?

  template <class Pred>
  size_t erase_if(Pred iPred); // returns the number of erased
private:
  std::vector<Value> m_data;
};

Dann weiter zum Unterricht:

class ParentClass
{
public:
  virtual void foo() const;
private:
  Container<ParentObj*> m_data;
};

class DerivedClass: public ParentClass
{
public:
  virtual void foo() const;
private:
  Container<DerivedObj*> m_data;
};

Versuchen Sie, Polymorphismus von der Wiederverwendung von Code zu trennen, und das Problem sollte einfacher werden.

1voto

Naveen Punkte 71443

std::vector< ParentObj* > y std::vector< DerivedObj* > sind zwei völlig unterschiedliche Typen und können daher nicht implizit in einen anderen umgewandelt werden. Was Sie tun können, ist die Konvertierung jedes ParentObj* a DerivedObj* mit dynamic_cast . Im Allgemeinen wird dies jedoch nicht als gute Praxis angesehen.

1voto

ur. Punkte 2860

Das ist mit der einfachen C++-Vererbung nicht möglich. Der Grund dafür ist, dass der Compiler nicht weiß, dass der Vektor nur Zeiger auf DerivedObj bei Verwendung in DerivedClass . Ich schließe mich Naveens Aussage über die dynamische Besetzung an.

Sie könnten zwei Vektoren verwenden std::vector< ParentObj* > mParent y std::vector< DerivedObj* > mDerived und eine virtuelle Add() Funktion. Die Basisimplementierung würde nur zu mParent . Die Add Funktion in DerivedClass würde auch dazu beitragen mDerived .

ParentClass hätte eine GetParentIterator() Funktion und DerivedClass eine weitere (zusätzliche) Funktion haben würde GetDerivedIterator() .

-1voto

Alexey Malistov Punkte 25541

Ihr Vererbungskonzept ist falsch.

DerivedClass darf nicht erben von ParentClass . ParentClass hat ein geschütztes Mitglied std::vector< ParentObj* > . Und DerivedClass muss ein anderes geschütztes Mitglied haben std::vector< DerivedObj* > .

Sie können die Vorlagenklasse

template<class T>
struct MyClass {
  protected:
    std::vector< T* > m_objects;
};

struct ParentClass : MyClass <ParentObj> {};
struct DerivedClass: MyClass <DerivedObj> {};

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X