web-dev-qa-db-ja.com

派生クラスへのC ++キャスト

派生クラスにキャストするにはどうすればよいですか?以下のアプローチはすべて次のエラーを与えます:

BaseTypeからDerivedTypeに変換できません。コンストラクターがソースタイプを取得できないか、コンストラクターのオーバーロード解決があいまいでした。

BaseType m_baseType;

DerivedType m_derivedType = m_baseType; // gives same error

DerivedType m_derivedType = (DerivedType)m_baseType; // gives same error

DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error
45
user346443

このように考えてください:

class Animal { /* Some virtual members */ };
class Dog: public Animal {};
class Cat: public Animal {};


Dog     dog;
Cat     cat;
Animal& AnimalRef1 = dog;  // Notice no cast required. (Dogs and cats are animals).
Animal& AnimalRef2 = cat;
Animal* AnimalPtr1 = &dog;
Animal* AnimlaPtr2 = &cat;

Cat&    catRef1 = dynamic_cast<Cat&>(AnimalRef1);  // Throws an exception  AnimalRef1 is a dog
Cat*    catPtr1 = dynamic_cast<Cat*>(AnimalPtr1);  // Returns NULL         AnimalPtr1 is a dog
Cat&    catRef2 = dynamic_cast<Cat&>(AnimalRef2);  // Works
Cat*    catPtr2 = dynamic_cast<Cat*>(AnimalPtr2);  // Works

// This on the other hand makes no sense
// An animal object is not a cat. Therefore it can not be treated like a Cat.
Animal  a;
Cat&    catRef1 = dynamic_cast<Cat&>(a);    // Throws an exception  Its not a CAT
Cat*    catPtr1 = dynamic_cast<Cat*>(&a);   // Returns NULL         Its not a CAT.

最初のステートメントを振り返ってみましょう。

Animal   animal = cat;    // This works. But it slices the cat part out and just
                          // assigns the animal part of the object.
Cat      bigCat = animal; // Makes no sense.
                          // An animal is not a cat!!!!!
Dog      bigDog = bigCat; // A cat is not a dog !!!!

動的キャストを使用する必要はほとんどありません。
これが、仮想メソッドがある理由です。

void makeNoise(Animal& animal)
{
     animal.DoNoiseMake();
}

Dog    dog;
Cat    cat;
Duck   duck;
Chicken chicken;

makeNoise(dog);
makeNoise(cat);
makeNoise(duck);
makeNoise(chicken);

私が考えることができる唯一の理由は、オブジェクトを基本クラスコンテナに保存した場合です。

std::vector<Animal*>  barnYard;
barnYard.Push_back(&dog);
barnYard.Push_back(&cat);
barnYard.Push_back(&duck);
barnYard.Push_back(&chicken);

Dog*  dog = dynamic_cast<Dog*>(barnYard[1]); // Note: NULL as this was the cat.

ただし、特定のオブジェクトをDogsにキャストする必要がある場合は、設計に根本的な問題があります。仮想メソッドを介してプロパティにアクセスする必要があります。

barnYard[1]->DoNoiseMake();
123
Martin York

dynamic_castは探しているものでなければなりません。

編集:

DerivedType m_derivedType = m_baseType; // gives same error

上記は、おそらくDerivedType型で定義されていないBaseType型を受け入れる代入演算子を呼び出そうとしているようです。

DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error

ここでは正しい道を歩んでいますが、dynamic_castを使用すると、指定された型に安全にキャストしようとし、失敗するとNULLが返されます。

ここでメモリに移動して、これを試してください(ただし、ベース型から派生型にキャストしているときにキャストがNULLを返すことに注意してください):

DerivedType * m_derivedType = dynamic_cast<DerivedType*>(&m_baseType);

M_baseTypeがポインターであり、実際にDerivedTypeのタイプを指している場合、dynamic_castは機能するはずです。

お役に立てれば!

7
Michael

ベースオブジェクトを派生型にキャストすることはできません-それはその型ではありません。

派生オブジェクトへのベースタイプポインターがある場合、dynamic_castを使用してそのポインターをキャストできます。例えば:

DerivedType D;
BaseType B;

BaseType *B_ptr=&B
BaseType *D_ptr=&D;// get a base pointer to derived type

DerivedType *derived_ptr1=dynamic_cast<DerivedType*>(D_ptr);// works fine
DerivedType *derived_ptr2=dynamic_cast<DerivedType*>(B_ptr);// returns NULL
5
Michael Kohne

まず、ダウンキャストの前提条件は、キャストするオブジェクトがキャスト先のタイプであることです。 dynamic_castを使用したキャストは、実行時にこの条件をチェックし(キャストされたオブジェクトに仮想関数がある場合)、失敗すると_bad_cast_をスローするか、NULLポインターを返します。コンパイル時のキャストは何もチェックせず、この前提条件が満たされない場合、tuの未定義の動作を引き起こすだけです。
今、コードを分析しています:

_DerivedType m_derivedType = m_baseType;
_

ここにキャスティングはありません。タイプDerivedTypeの新しいオブジェクトを作成し、m_baseType変数の値で初期化しようとします。

次の行はそれほど良くありません:

_DerivedType m_derivedType = (DerivedType)m_baseType;
_

ここでは、_m_baseType_値で初期化されたDerivedTypeタイプの一時的なものを作成しています。

最後の行

_DerivedType * m_derivedType = (DerivedType*) & m_baseType;
_

BaseTypeDerivedTypeの直接または間接のパブリックベースクラスである場合、コンパイルする必要があります。とにかく2つの欠陥があります:

  1. 非推奨のCスタイルキャストを使用します。そのようなキャストの適切な方法は
    static_cast<DerivedType *>(&m_baseType)
  2. キャストされたオブジェクトの実際のタイプはDerivedTypeではありません(_BaseType m_baseType;_として定義されたため、_m_derivedType_ポインターを使用すると未定義の動作になります。
2
Tadeusz Kopec