クラス A があり、クラス B と C がそれを継承しているとします。次に、A への参照の配列を作成し、B と C で埋めます。ここで、すべての C を削除することにしました。returnType() 関数のような冗長なことをせずに、配列の各フィールドが実際に保持している型を確認する方法はありますか?
編集:「Aの配列」を「Aへの参照の配列」に修正しました。
クラス A があり、クラス B と C がそれを継承しているとします。次に、A への参照の配列を作成し、B と C で埋めます。ここで、すべての C を削除することにしました。returnType() 関数のような冗長なことをせずに、配列の各フィールドが実際に保持している型を確認する方法はありますか?
編集:「Aの配列」を「Aへの参照の配列」に修正しました。
As の配列を作成して B と C で埋めることはできません。それらは
As にスライスされます。B へのポインターと C へのポインターを設定できる A へのポインターの配列を作成できます。
この状況で何かのタイプを確認するには、動的キャストを使用します。
// create B or C randomly
A * a = rand() % 2 ? new B : new C;
if ( dynamic_cast <B *> ( a ) ) {
// it's a B
}
else {
// it isn't (must be C in this case)
}
理想的には、そこに C を入れたくないのはどのような機能なのかを把握する必要があります。次に、そのプロパティを公開する仮想関数を追加します。このようにして、同じ不要なプロパティを持つクラス D を追加すると、引き続き正しく動作します。
class A
{
public:
virtual bool IsFrobbable() { return true; }
};
class B : public A
{
};
class C : public A
{
public:
virtual bool IsFrobbable() { return false; }
};
int main()
{
vector<A *> vA;
vA.push_back(new A());
vA.push_back(new B());
vA.push_back(new C());
vA.erase(remove_if(vA.begin(), vA.end(), not1(mem_fun(&A::IsFrobbable))));
// Now go ahead and frob everything that's left
}
B を格納することはできません。コンパイラはうめきます。
これは、A の配列が実際に A へのポインターの配列である場合にのみ機能します。そうでない場合は、スライスの問題が発生します。
当面の問題に関しては、A に仮想関数 getClassName を与え、それをサブクラスで適切にオーバーライドし、その結果を使用して必要な動作を提供する方がよいでしょう。
C++ で参照の配列を作成することはできません。
A
ただし、へのポインターの配列を作成することは可能です。その場合、A
少なくとも 1 つの仮想関数が宣言されていれば、C++ のランタイム型推論 (RTTI) メカニズムを使用して、やりたいことを実行できます。
A* arr[10];
fill_with_as_bs_and_cs(arr);
for (int i = 0; i < 10; ++i) {
if (dynamic_cast<C*>(arr[i])) {
arr[i] = 0; // You can't really "remove" things from an array...
}
}
ただし、これは最も維持しやすいアプローチではありません。 aC
と anをA
区別する必要があるときはいつでも、このif
テストを使用する必要A
があります。この「型テスト」を実行しているコード内のすべての場所を更新する必要があります。コードベースが大きくなるにつれて、見落としがちな場所がすぐに見つかります。
一般に、必要に応じて各クラスでオーバーライドされる仮想関数を使用する方がはるかに保守性が高くなります。この特定のケースでは、配列から削除する必要があるすべての派生クラス オブジェクトによって共有される一般的な基準を確立します。たとえば、オブジェクトがblargableA
の場合は削除する必要があるとしましょう。次に、仮想関数を記述し、テストします。その代わりに。bool isBlargable()