Frage

Ich werde Ausdruck dies in Form eines Beispiels, um es klar.

Sagen, dass ich einen Vektor von Tieren haben und ich möchte durch das Feld gehen und sehen, ob die Elemente sind entweder Hunde oder Katzen?

class Dog: public Animal{/*...*/};
class Cat: public Animal{/*...*/};

int main()
{
vector<Animal*> stuff;
//cramming the dogs and cats in...

for(/*all elements in stuff*/)
//Something to the effect of:  if(stuff[i].getClass()==Dog) {/*do something*/}

}

Ich hoffe, dass ist irgendwie klar. Ich weiß, über typeid, aber ich habe nicht wirklich Dog-Objekt zu vergleichen es und ich würde ein Hund-Objekt erstellen vermeiden mag, wenn ich kann.

Gibt es eine Möglichkeit, dies zu tun? Vielen Dank im Voraus.

War es hilfreich?

Lösung

Wie andere bemerkt hat, sollten Sie weder die typeid verwenden, noch die dynamic_cast Betreiber den dynamischen Typ von dem, was Ihre Zeiger auf bekommen. virtuelle Funktionen erstellt wurden, diese Art von Gemeinheit zu vermeiden.

Wie auch immer, hier ist was Sie tun, wenn Sie auf wirklich wollen, es zu tun (beachten Sie, dass ein Iterator dereferencing geben Ihnen Animal* Wenn Sie also Sie **it wird eine Animal& erhalten.):

for(std::vector<Animal*>::iterator it = v.begin(); it != v.end(); ++it) {
    if(typeid(**it) == typeid(Dog)) {
        // it's a dog
    } else if(typeid(**it) == typeid(Cat)) {
        // it's a cat
    }
}

Beachten Sie die typeid Operator Typen gelten kann sich auch wie oben gezeigt. Sie brauchen nicht ein Objekt für diese zu schaffen. Beachten Sie auch die typeid Art und Weise funktioniert nicht, wenn Sie es einen Zeiger wie typeid(*it) passieren. es so können Sie Zeit nur typeid(Animal*) geben, die nicht nützlich ist.

Ähnliche, dynamic_cast können verwendet werden:

for(std::vector<Animal*>::iterator it = v.begin(); it != v.end(); ++it) {
    if(Dog * dog = dynamic_cast<Dog*>(*it)) {
        // it's a dog (or inherited from it). use the pointer
    } else if(Cat * cat = dynamic_cast<Cat*>(*it)) {
        // it's a cat (or inherited from it). use the pointer. 
    }
}

Beachten Sie, dass in beiden Fällen Ihr Tiertyp Polymorph sein sollte. Das bedeutet, muss sie oder zumindest eine virtuelle Funktion geerbt hat.

Andere Tipps

Sie können mit dynamic_cast, solange der Vektor Tier-Zeiger enthält.

vector <Animal *> stuff;

for(int i=0;i<stuff.size();i++) {
    Dog *pDog = dynamic_cast <Dog *> (stuff[i]);
    if(pDog) {
        // do whatever with the dog
    }

    Cat *pCat = dynamic_cast <Cat *> (stuff[i]);
    if(pCat) {
        // and so on
    }
}

aber sollten Sie sich bewusst sein, dass dies in der Regel nicht die beste Praxis. Sie sollten versuchen, mit Polymorphismus, nicht gegen sie zu arbeiten. Mit anderen Worten, versuchen, eine virtuelle Animal Funktion zu schreiben, die Dog und Cat überschreiben, und lassen Sie die Compiler automatisch die richtigen nennen.

(Auch dynamic_cast ist relativ langsam, so zu viele von ihnen wird die Leistung beeinträchtigt;., Während ein virtueller Funktionsaufruf allgemeinen ist nur eine einzige Anweisung)

Sind Sie sicher, dass Sie das tun? Was Sie vorhaben, ist das genaue Gegenteil von Polymorphismus zu tun, und Polymorphismus ist das Beste, was in der objektorientierten Programmierung.

Grob gesagt: Tun Sie etwas nicht tun , wenn Sie Tier ein Hund ist; lassen Sie die Tier Hierarchie wissen, was zu tun ist, wenn eine ihrer Aufgaben ein Hund ist! :)

Wenn Sie wirklich Ihre Anwendungsebene müssen Hunde gegen Nicht-Hunde zu identifizieren, sollten Sie vermeiden RTTI verwenden (dynamic_cast und typeid) und machen dieses Wissen explizit in Ihrer Klassenhierarchie.

for (size_t i = 0; i != v.size(); ++i) {
    if (v[i]->isDog()) { v->cleanupPoop(); }
}

Es gibt einige kleinere Performance-Vorteile, aber der Hauptvorteil die notwendige Verhalten in der Klasse Schnittstelle zu Programmierern aussetzt. RTTI (die so begrenzt wie es ist) nicht, um eine Klassenhierarchie erforderlich funktionieren.

Nun, zusammen mit dem, was andere Leute schon gesagt haben, ist es wahrscheinlich, dass die isDog() Funktion in etwas Refactoring werden könnte, die nicht die Kenntnis der gesamten Hierarchie erfordert nicht up-front (wie needsPoopCleanup()). Wie alle anderen gesagt, sind Sie die Vorteile von Polymorphismus zu verlieren bedingt, wenn Ihre Anwendungslogik auf dem Objekt basiert ausführt Typ sowieso.

Sie können den typeid Operator verwenden, dies zu tun, z.

if (typeid(stuff[i].getClass())==typeid(Dog))

Dies kann nicht fangen, wenn es sich um eine abgeleitete Klasse von Dog ist, though. Sie können eine dynamic_cast dafür. Allerdings ist jede Verwendung von typeid oder dynamic_cast oft Anzeichen für einen Konstruktionsfehler. Normalerweise Sie brauchen nicht zu wissen, was Ihre abgeleiteten Typen sind, und es gibt wahrscheinlich eine bessere Art und Weise, den Polymorphismus umfasst. Es ist schwer, die richtige Beratung ohne konkretes Beispiel zu geben, though.

mit virtuellen Funktionen:

Wie bereits von anderen Antworten erwähnt, wird oft virtuelle Funktionen tatsächlich ausreichend genug, und ist die „C ++“ Denkweise. Hier ist ein Beispiel für die Verwendung virtueller Funktionen:

#include<iostream>
#include<vector>
using namespace std;

/////////////

class Animal {
  public:
    virtual void move() { cout << "animal just moved" << endl; }
};
class Dog : public Animal {
  public:
    void move() { cout << "dog just moved" << endl; }
};
class Cat : public Animal {
  public:
    void move() { cout << "cat just moved" << endl; }
};

void doSomethingWithAnimal(Animal *a) {
  a->move();
}

/////////////

int main() {
  vector<Animal*> vec;
  vector<Animal*>::iterator it;

  Animal *a = new Animal;
  Dog *d = new Dog;
  Cat *c = new Cat;

  vec.push_back(a);
  vec.push_back(d);
  vec.push_back(c);

  it = vec.begin();

  while( it != vec.end() ) {
    doSomethingWithAnimal(*it);

    it++;
  }

  return 0;
}

Falls dies nicht ausreichen wird, dann haben andere Wissenschaftler bereits Antworten geschrieben, die eigentlich bedingte Logik anstelle von polymerisierten Logik.

Die akzeptierte Antwort ist richtig, aber man sollte wissen, dass es eine andere Option als auch ist, die nicht erwähnt worden ist. Sie könnten eine virtuelle Funktion in der Klasse Tier namens „Typ ()“, die einen int oder eine Zeichenfolge (oder jede Art, die vergleichbar ist) zurückkehren können.

So zum Beispiel:

class Animal {
    /*...*/
public:
    virtual std::string type() const { return "animal"; }
};

class Dog: public Animal{
    /*...*/
public:
    virtual std::string type() const { return "dog"; }
};

class Cat: public Animal{
    /*...*/
public:
    virtual std::string type() const { return "cat"; }
};

Auf diese Weise könnten Sie einfach tun:

if(array[i]->type() == "dog") { }

Der Typ Funktion könnte etwas zurückgeben (int einzigartig für jeden abgeleiteten Typen funktionieren würde, aber Strings illustrieren es besser).

Sie einfach eine weitere Option.

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