1

基本クラス(car)と基本クラス()を継承するクラスがありhondaます。

class car
{
    virtual void polymorphic_class()
    {   }
};

class honda : public car
{   };


次のコードを使用してクラスをキャストすると、nullポインターが取得されます。

list<car> cars;
honda h;
cars.push_back(h);
honda* h_ptr = dynamic_cast<honda*>(&cars.back());
// h_ptr is NULL

なんで?オブジェクトを適切にキャストするにはどうすればよいですか?

4

3 に答える 3

4

これが機能しない理由は、オブジェクトのスライスです。のオブジェクトはcarsもはやhondasではなく、単なる車です。

ポインターまたはスマートポインターのベクトルが必要です。

list<car*> cars;
honda h;
cars.push_back(&h);
honda* h_ptr = dynamic_cast<honda*>(cars.back());

私は実際にデザインを変更してcar抽象化します(純粋な仮想デストラクタなど)。そうすれば、コンパイルエラーも発生します。

于 2012-07-05T11:31:54.767 に答える
2

ポリモーフィズムは、オブジェクトインスタンスではなく、ポインタと参照で機能します。

この場合、リストにはcar派生タイプではなく、タイプのオブジェクトが含まれます。を挿入するhondaと、パーツがコピーされcar、残りは無視されます。これは、スライスと呼ばれることもあります。

ポリモーフィズムの場合、ポインターのリストを使用できます。

list<car*> cars {new honda};
honda * h_ptr = dynamic_cast<honda*>(cars.back()); // should be a valid pointer

注:new私の例のようにを使用して割り当てる場合は、それらのいずれかを忘れないでください。または、生のポインターではなく、deleteスマートポインター(など)を格納してください。std::unique_ptr<car>基本クラスのポインタを使用してオブジェクトを削除するには、仮想デストラクタも必要です。

基本クラスを抽象化することで、スライスの問題を回避できます。純粋仮想関数が含まれている場合、そのタイプのオブジェクトをインスタンス化することはできず、それらの関数をオーバーライドする派生型のみをインスタンス化できます。

class car
{
    virtual ~car() {}
    virtual void do_something() = 0;
};

class honda : public car
{
    void do_something() {}
};

抽象インターフェースが実際に必要ない場合(たとえば、dynamic_cast仮想関数ではなくを使用して派生クラスの機能にのみアクセスする場合)、代わりにデストラクタを純粋仮想にすることができます。その場合、派生クラスは明示的に何もオーバーライドする必要はありません。基本クラスのデストラクタは引き続き実装する必要があり、言語の癖のため、その実装はクラス定義の外にある必要があります。

class car
{
    virtual ~car() = 0;
};
inline car::~car() {}

class honda : public car {};

仮想関数によるポリモーフィズムは通常、より効率的で便利であるため、これはやや珍しいアプローチです。

于 2012-07-05T11:53:26.577 に答える
0

これを試して

list<car*> cars;
honda *h = new honda();
cars.push_back(h);
honda* h_ptr = dynamic_cast<honda*>(cars.back());

これは機能します。

于 2012-07-05T11:33:22.413 に答える