質問

より明確にするために、これを例の形で表現します。

動物のベクトルがあり、配列を調べて、要素が犬か猫かを確認したい場合

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*/}

}

それが一種の明確であることを願っています。 typeidについては知っていますが、比較するDogオブジェクトは実際にはないので、できればDogオブジェクトの作成を避けたいと思います。

これを行う方法はありますか?事前に感謝します。

役に立ちましたか?

解決

他の人が指摘したように、ポインターが指すものの動的な型を取得するために、 typeid dynamic_cast 演算子も使用しないでください。この種の厄介さを避けるために、仮想関数が作成されました。

とにかく本当にやりたい場合はここで行います(イテレータを逆参照すると Animal * が得られることに注意してください。 * it を取得すると、 Animal&amp; ):

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
    }
}

上記のように、 typeid 演算子を型自体にも適用できます。このためにオブジェクトを作成する必要はありません。また、 typeid(* it)のようなポインターを渡すと、typeidの方法が機能しないことに注意してください。そのように使用すると、 typeid(Animal *)が得られますが、これは有用ではありません。

同様に、 dynamic_cast を使用できます:

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. 
    }
}

どちらの場合も、動物の種類は多形である必要があります。つまり、少なくとも1つの仮想関数を持っているか、継承している必要があります。

他のヒント

ベクターに動物ポインターが含まれている限り、 dynamic_cast を使用できます。

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
    }
}

ただし、これは一般的にベストプラクティスではないことに注意してください。ポリモーフィズムに反対するのではなく、ポリモーフィズムを扱うようにしてください。言い換えれば、 Dog Cat がオーバーライドする仮想 Animal 関数を記述し、コンパイラーが自動的に正しい関数を呼び出すようにします。

(また、 dynamic_cast は比較的遅いので、それらが多すぎるとパフォーマンスが低下します。一方、仮想関数呼び出しは一般にただ1つの命令です。)

本当に実行しますか?あなたがやろうとしていることは、ポリモーフィズムの正反対であり、ポリモーフィズムはオブジェクト指向プログラミングで最高のものです。

大まかに言えば、動物が犬の場合は何かしないでください。オブジェクトの1つが犬である場合、動物の階層に何をすべきかを知らせます! :)

犬と非犬を識別するためにアプリケーションレベルが本当に必要な場合は、RTTI( dynamic_cast typeid )の使用を避け、その知識をクラス階層。

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

パフォーマンスには若干の利点がありますが、主な利点は、クラスインターフェイスで必要な動作をメンテナンスプログラマに公開することです。クラス階層が機能するために、RTTI(現状のまま)は必要ありません。

今、他の人が言ったことに加えて、 isDog()関数は、階層全体の知識を必要としないものにリファクタリングできる可能性があります(< code> needsPoopCleanup())。他のみんなが言ったように、アプリケーションロジックがオブジェクトタイプに基づいて条件付きで実行されると、ポリモーフィズムの利点が失われます。

typeid 演算子を使用してこれを行うことができます。例:

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

ただし、 Dog の派生クラスの場合はキャッチできません。そのために dynamic_cast を使用できます。ただし、 typeid または dynamic_cast の使用は多くの場合、設計上の欠陥を示しています。通常、派生型が何であるかを知る必要はありません。多型を含むより良い方法がおそらくあります。ただし、実際の例を使用せずに適切なアドバイスを提供することは困難です。

仮想関数の使用:

他の応答で示されているように、仮想関数を使用すれば、実際には十分であることが多く、「C ++」考え方。仮想関数の使用例を次に示します。

#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;
}

これで十分でない場合、他の人はすでに重合ロジックの代わりに条件ロジックを実際に使用する回答をすでに投稿しています。

受け入れられた答えは正しいですが、言及されていない別のオプションがあることを知っておく必要があります。 Animalクラスに&quot; type()&quot;という仮想関数を含めることができます。 intまたは文字列(または同等の任意の型)を返す可能性があります。

したがって、たとえば:

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"; }
};

この方法でできること:

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

type関数は何でも返すことができます(各派生型に固有のintも機能しますが、文字列はそれをよりよく示します)。

単に別のオプション。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top