7 Stimmen

Ein Zeiger, zwei verschiedene Klassen in c++

Angenommen, ich habe zwei Strukturen a und b, die jeweils mehrere Variablen enthalten (die meisten Variablen sind C++-Kerntypen, aber nicht alle).

Gibt es eine Möglichkeit, einen Zeiger mit dem Namen c zu erstellen, der auf eine von ihnen zeigen kann? Alternativ, gibt es eine Möglichkeit, eine Menge zu erstellen, die eine von ihnen halten kann?

Danke

0voto

xtofl Punkte 39285

Auch wenn du das machen kannst, was würde dieser Zeiger bedeuten? Wenn irgendein Teil deiner Anwendung den Zeiger auf 'entweder a oder b' erhält, kann er nicht viel damit anfangen, es sei denn, du gibst zusätzliche Typinformationen.

Zusätzliche Typinformationen bereitzustellen führt zu Client-Code wie

if( p->type == 'a' ) {
   ... spezifische Dinge für a
} else if( p->type == 'b' ) {
   ... spezifische Dinge für b
} ...

Was nicht sehr nützlich ist.

Es wäre besser, die 'typspezifische Eigenschaft' dem Objekt selbst zu übergeben, was die Natur des objektorientierten Designs ist, und C++ hat dafür ein sehr gutes Typsystem.

class Interface {
 public:
    virtual void doClientStuff() = 0; // 
    virtual ~theInterface(){};
};

class A : public Interface {
    virtual void doClientStuff(){ ... spezifische Dinge für a }
};

class B : public Interface {
    virtual void doClientStuff(){ ... spezifische Dinge für b }
};

Und dann wird dein Client-Code weniger typbewusst, da das Typumschalten von C++ für dich erledigt wird.

void clientCode( Interface* einObjekt ) {
   einObjekt->doClientStuff();
}

Interface* i = new A();
Interface* j = new B();

clientCode( i );
clientCOde( j );

0voto

Michael Aaron Safyan Punkte 90663

Es gibt mehrere Möglichkeiten, dies zu tun:

  1. Verwenden eines allgemeineren Basistyps, wenn es eine Vererbungsbeziehung gibt.
  2. Verwenden von void* und explizitem Casten, wo erforderlich.
  3. Erstellen einer Wrapper-Klasse mit der für #1 benötigten Vererbungsbeziehung.
  4. Verwenden eines diskriminierenden Containers über union.

Da andere bereits die ersten drei Optionen beschrieben haben, werde ich die vierte beschreiben. Grundsätzlich verwendet ein diskriminierender Container einen union-Typ, um den Speicher eines einzigen Objekts zur Speicherung von mehreren verschiedenen Werten zu nutzen. Typischerweise wird eine solche Union in einer Struktur zusammen mit einem Enum oder Integraltyp zur Unterscheidung verwendet, welcher Wert sich derzeit im Unionstyp befindet. Als Beispiel:

// Deklarationen ...
class FirstType;
class SecondType;

union ZeigerAufErstesOderZweites {
   FirstType* firstptr;
   SecondType* secondptr;
};

enum ERSTES_ODER_ZWEITES_TYPE {
   ERSTES_TYP,
   ZWEITES_TYP
};

struct ZeigerAufErstesOderZweitesContainer {
   ZeigerAufErstesOderZweites zeiger;
   ERSTES_ODER_ZWEITES_TYPE welches;
};

// Beispielverwendung...

void OperateOnPointer(ZeigerAufErstesOderZweitesContainer container) {
    if (container.welches == ERSTES_TYP) {
       MachEtwasMit(container.zeiger.firstptr);
    } else {
       MachEtwasAnderesMit(container.zeiger.secondptr);
    }
}

Beachten Sie, dass in dem folgenden Code "firstptr" und "secondptr" tatsächlich zwei verschiedene Ansichten derselben Variablen sind (dh derselbe Speicherort), da Unionen Speicherplatz für ihre Inhalte teilen.

Beachten Sie, dass obwohl dies eine mögliche Lösung ist, ich dies ernsthaft nicht empfehlen würde. Diese Art von Lösung ist nicht sehr wartbar. Ich empfehle dringend, Vererbung zu verwenden, wenn dies möglich ist.

0voto

Gilco Punkte 1276

Abstrakte Klasse !!!! -- einfache Lösungen

Um eine Basisklasse zu haben, die als Zeiger auf mehrere abgeleitete Unterklassen verwendet werden kann. (kein Casting erforderlich)

Abstrakte Klasse wird definiert, wenn Sie eine virtuelle Methode darin verwenden. Dann implementieren Sie diese Methode in der Unterklasse... einfach:

// abstrakte Basisklasse
#include 
using namespace std;

class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area (void) =0;
};

class Rechteck: public Polygon {
  public:
    int area (void)
      { return (width * height); }
};

class Dreieck: public Polygon {
  public:
    int area (void)
      { return (width * height / 2); }
};

int main () {
  Polygon * ppoly1 = new Rechteck (4,5);
  Polygon * ppoly2 = new Dreieck (4,5);
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  cout << ppoly1->area() << '\n';
  cout << ppoly2->area() << '\n';
  return 0;
}

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