スーパークラスポインタC++からサブクラスメンバーにアクセスする
-
23-09-2019 - |
質問
私はカスタムクラスの学生オブジェクトの配列を持っています。CourseStudentとResearchStudentはどちらもStudentから継承し、Studentのすべてのインスタンスはこれらのいずれかです。
私は配列を通過し、各学生のサブタイプを決定し、それらのサブタイプ固有のメンバー関数を呼び出す関数を持っています。
問題は、これらの関数がオーバーロードされていないため、Studentに見つからないため、コンパイラが大騒ぎになることです。
私は学生へのポインタを持っている場合、その学生のサブタイプへのポインタを取得する方法はありますか?コンパイル時エラーを回避するために、ここで何らかの偽のキャストを作成する必要がありますか?
解決
ダイナミックキャストが必要です:
Student * s = new ...; // create student of some sort
if ( ResearchStudent * r = dynamic_cast<ReasearchStudent*>( s ) ) {
r->ResFunc();
}
else if ( CourseStudent * c = dynamic_cast<CourseStudent*>( s ) ) {
c->CourseFiunc();
}
else {
throw "unknown student type";
}
これは、クラスに少なくとも1つの仮想関数がある場合、コンパイラによって維持されるタイプ情報を使用することに注意してください - 他のすべてが失敗した場合、Destructor仮想を作成します(この場合は、Anwayに必要な場合)。独自のタイプ情報を維持するには、常にこのアプローチを好む必要があります。
他のヒント
最良のことは、仮想関数を使用することです:
class Student
{
// ...
virtual void SpecificFunction() = 0; /* = 0 means it's abstract; it must be implemented by a subclass */
// ...
};
class CourseStudent
{
void SpecificFunction() { ... }
};
それからあなたはすることができます:
Student *student;
student->SpecificFunction();
(より悪い)代替手段を使用することができます dynamic_cast
:
Student *student;
CourseStudent *cs = dynamic_cast<CourseStudent *>(student);
if (cs) {
/* student is a CourseStudent.. */
cs->SpecificFunction();
}
サブクラスメンバー関数はそれらのサブクラスに固有のものであるため、仮想関数はここでは不適切です(たとえば、CourseStudentにはユニットのリストがありますが、研究者はそうではないので、研究者のGetUnits()関数の実装はまったく意味がありません)
ダイナミックと静的キャストについて少し読み上げました( cplusplus.comタイプキャスト )、そしてこの例では、静的キャストがより適切だと思います。
static_castの一般的な欠点は、サブタイプに鋳造されているオブジェクトが実際には他のサブタイプではなく、サブタイプではないことを確認するために、実行時にチェックを実行しないことです。この場合、タイプを実行する前にタイプを具体的にチェックしています(サブクラスコンストラクターに設定されており、突然変異体がないプライベートデータメンバーを使用)。 。ダイナミックキャストにはタイプチェックを実行するためにより多くのランタイムリソースが必要なため、静的キャストがより効率的です。
メンバーが予想されるタイプでない可能性がある場合、静的キャストは適切ではないので、私はダイナミックキャストに行きます(これは割り当てであるため、提出されるとコードを維持する必要がないので、後で誰かがそれを台無しにするリスクはありません)。
これは、ほぼ間違いなく、基本クラスで純粋な仮想メンバー関数を使用し、実際の作業を行う派生クラスでオーバーライドする場合です。
あなたが必要です static_cast
そのために。これらの関数は基本クラスの仮想メンバーではないため、ポインターツーベースクラスのポインターを使用して呼び出すことはできません。オブジェクトの実際のタイプに明示的にキャストする必要があります。
この問題は通常、仮想関数で最適に解決されます。コードをチェックするオブジェクトタイプがもう必要ありません。バグのコードが少なく、表面が少なくなります。