18.10 Dynamic casting
https://www.learncpp.com/cpp-tutorial/dynamic-casting/
レッスン8.5--
鋳造の概念を議論した.
このレッスンではdynamiccastというもう一つのタイプを紹介します
マルチステート性を処理する場合、ベースクラスポインタを持つときに派生クラスの情報にアクセスしたいことがよくあります.
次に例を示します
1つの方法はvirtual functionを使用することです
しかし、ベースオブジェクトを指すベースポイントについては、どうすればいいのでしょうか.
これは意味がない.ベースクラスを汚染する可能性があります
C++でDerived pointerをBase pointerに暗黙的に変換することを知っている.このプロセスをupcastingと呼ぶ
しかし、ベースポインタをDerivedポインタに変換する方法があればどうなるのでしょうか.では、Derived::getName()を直接呼び出すことができます.仮想化
c++はcastingオペレータでdynamic castをサポートします
これはこの目的に使用できます.
ダイナミック鋳造にはいくつかの異なる機能がありますが、ダイナミック鋳造の最も一般的な用途はBaseクラスポインタをDerivedクラスポインタに変換することです.
これはupcastingという反意語downscastです
dynamic castはstatic castのように使用できます
ここに例があります
その後dynamic castで再びDerived pointerを使用して降格します
上記の例は正常に動作しています.bobjectはDerived Objectへのポインタなので
しかし、そうでなければ、どうなるのでしょうか.
これにより、getObjectのパラメータをfalseに簡単に変換してテストすることができます.
このようなdynamic castを試してみると失敗するかもしれません
dynamic castに失敗するとnull pointerになります
したがって、次のコードを記述する必要があります.
Always ensure your dynamic casts actually succeeded by checking for a null pointer result.
dynamiccastは、実行時に一貫性チェック(変換可能性を確保)を行い、パフォーマンスが低下します.
また、ここではdynamic castによるダウンロードに失敗する場合もあります. With protected or private inheritance. For classes that do not declare or inherit any virtual functions (and thus don’t have a virtual table). In certain cases involving virtual base classes (see this page for an example of some of these cases, and how to resolve them).
Downcastingはstatic castであってもよい.最大の違いはstatic castの場合、ランタイムタイプをチェックしないことです.これはstatic castの使用が速いことを意味しますが、危険にもなります.
ベースポインタがDerived objectを指していなくても、BasepointerからDerived pointerへの変換に成功します.これは私たちの何気ない動作です.
そこで、static castでDowncastingを行いたい場合は、まずDerived class objectを指すかどうかを確認します.
次の例ではvirtual functionを使用して確認します.
上記のすべての例はpointerのdynamic castingに表示されます(より一般的です).
dynamiccastはreferenceにも使用できます.これはdynamic castがポインタと一緒に動作する方法に似ています
新しいプログラマーは、式static castとdynamic castの使用に戸惑うことがあります.
答えは簡単です.downcastでない場合はstatic castを使用します.
downcastの場合、通常dynamiccastが適切です.
しかし、仮想迂回の方法も考えなければならない.
一部の開発者はdynamic castが悪いクラス設計を表していると信じています
代わりにvirtual functionを使います
通常、downcastingよりvirtualfunctionの方が人気があります
しかし、downcastingがより良い選択である場合もあります. When you can not modify the base class to add a virtual function (e.g. because the base class is part of the standard library) When you need access to something that is derived-class specific (e.g. an access function that only exists in the derived class) When adding a virtual function to your base class doesn’t make sense (e.g. there is no appropriate value for the base class to return). Using a pure virtual function may be an option here if you don’t need to instantiate the base class.
レッスン8.5--
鋳造の概念を議論した.
このレッスンではdynamiccastというもう一つのタイプを紹介します
The need for dynamic_cast
マルチステート性を処理する場合、ベースクラスポインタを持つときに派生クラスの情報にアクセスしたいことがよくあります.
次に例を示します
#include <iostream>
#include <string>
class Base
{
protected:
int m_value{};
public:
Base(int value)
: m_value{value}
{
}
virtual ~Base() = default;
};
class Derived : public Base
{
protected:
std::string m_name{};
public:
Derived(int value, const std::string& name)
: Base{value}, m_name{name}
{
}
const std::string& getName() const { return m_name; }
};
Base* getObject(bool returnDerived)
{
if (returnDerived)
return new Derived{1, "Apple"};
else
return new Base{2};
}
int main()
{
Base* b{ getObject(true) };
// how do we print the Derived object's name here, having only a Base pointer?
delete b;
return 0;
}
上記のプログラムでは、getObject関数は常にBase pointerを返します.ただしpointerはBaseまたはDerived objectを指すことができる.この場合、ポインタがDelived objectを指している場合、Delived::getName()を呼び出すにはどうすればいいですか?1つの方法はvirtual functionを使用することです
しかし、ベースオブジェクトを指すベースポイントについては、どうすればいいのでしょうか.
これは意味がない.ベースクラスを汚染する可能性があります
C++でDerived pointerをBase pointerに暗黙的に変換することを知っている.このプロセスをupcastingと呼ぶ
しかし、ベースポインタをDerivedポインタに変換する方法があればどうなるのでしょうか.では、Derived::getName()を直接呼び出すことができます.仮想化
dynamic_cast
c++はcastingオペレータでdynamic castをサポートします
これはこの目的に使用できます.
ダイナミック鋳造にはいくつかの異なる機能がありますが、ダイナミック鋳造の最も一般的な用途はBaseクラスポインタをDerivedクラスポインタに変換することです.
これはupcastingという反意語downscastです
dynamic castはstatic castのように使用できます
ここに例があります
int main()
{
Base* b{ getObject(true) };
Derived* d{ dynamic_cast<Derived*>(b) }; // use dynamic cast to convert Base pointer into Derived pointer
std::cout << "The name of the Derived is: " << d->getName() << '\n';
delete b;
return 0;
}
getObjectを受信したBase pointerはDerived objectを指すその後dynamic castで再びDerived pointerを使用して降格します
dynamic_cast failure
上記の例は正常に動作しています.bobjectはDerived Objectへのポインタなので
しかし、そうでなければ、どうなるのでしょうか.
これにより、getObjectのパラメータをfalseに簡単に変換してテストすることができます.
このようなdynamic castを試してみると失敗するかもしれません
dynamic castに失敗するとnull pointerになります
したがって、次のコードを記述する必要があります.
int main()
{
Base* b{ getObject(true) };
Derived* d{ dynamic_cast<Derived*>(b) }; // use dynamic cast to convert Base pointer into Derived pointer
if (d) // make sure d is non-null
std::cout << "The name of the Derived is: " << d->getName() << '\n';
delete b;
return 0;
}
if(d)で空のポインタであるかどうかをチェックすると、d->getName()へのアクセスが許可されます.Rule
Always ensure your dynamic casts actually succeeded by checking for a null pointer result.
dynamiccastは、実行時に一貫性チェック(変換可能性を確保)を行い、パフォーマンスが低下します.
また、ここではdynamic castによるダウンロードに失敗する場合もあります.
Downcasting with static_cast
Downcastingはstatic castであってもよい.最大の違いはstatic castの場合、ランタイムタイプをチェックしないことです.これはstatic castの使用が速いことを意味しますが、危険にもなります.
ベースポインタがDerived objectを指していなくても、BasepointerからDerived pointerへの変換に成功します.これは私たちの何気ない動作です.
そこで、static castでDowncastingを行いたい場合は、まずDerived class objectを指すかどうかを確認します.
次の例ではvirtual functionを使用して確認します.
#include <iostream>
#include <string>
// Class identifier
enum class ClassID
{
base,
derived
// Others can be added here later
};
class Base
{
protected:
int m_value{};
public:
Base(int value)
: m_value{value}
{
}
virtual ~Base() = default;
virtual ClassID getClassID() const { return ClassID::base; }
};
class Derived : public Base
{
protected:
std::string m_name{};
public:
Derived(int value, const std::string& name)
: Base{value}, m_name{name}
{
}
const std::string& getName() const { return m_name; }
virtual ClassID getClassID() const { return ClassID::derived; }
};
Base* getObject(bool bReturnDerived)
{
if (bReturnDerived)
return new Derived{1, "Apple"};
else
return new Base{2};
}
int main()
{
Base* b{ getObject(true) };
if (b->getClassID() == ClassID::derived)
{
// We already proved b is pointing to a Derived object, so this should always succeed
Derived* d{ static_cast<Derived*>(b) };
std::cout << "The name of the Derived is: " << d->getName() << '\n';
}
delete b;
return 0;
}
面倒に考えたくないならdynamic castをそのまま使いましょうdynamic_cast and references
上記のすべての例はpointerのdynamic castingに表示されます(より一般的です).
dynamiccastはreferenceにも使用できます.これはdynamic castがポインタと一緒に動作する方法に似ています
#include <iostream>
#include <string>
class Base
{
protected:
int m_value;
public:
Base(int value)
: m_value{value}
{
}
virtual ~Base() = default;
};
class Derived : public Base
{
protected:
std::string m_name;
public:
Derived(int value, const std::string& name)
: Base{value}, m_name{name}
{
}
const std::string& getName() const { return m_name; }
};
int main()
{
Derived apple{1, "Apple"}; // create an apple
Base& b{ apple }; // set base reference to object
Derived& d{ dynamic_cast<Derived&>(b) }; // dynamic cast using a reference instead of a pointer
std::cout << "The name of the Derived is: " << d.getName() << '\n'; // we can access Derived::getName through d
return 0;
}
c++はnull参照がないため、変換に失敗するとstd::bad castが返されます.dynamic_cast vs static_cast
新しいプログラマーは、式static castとdynamic castの使用に戸惑うことがあります.
答えは簡単です.downcastでない場合はstatic castを使用します.
downcastの場合、通常dynamiccastが適切です.
しかし、仮想迂回の方法も考えなければならない.
Downcasting vs virtual functions
一部の開発者はdynamic castが悪いクラス設計を表していると信じています
代わりにvirtual functionを使います
通常、downcastingよりvirtualfunctionの方が人気があります
しかし、downcastingがより良い選択である場合もあります.
Reference
この問題について(18.10 Dynamic casting), 我々は、より多くの情報をここで見つけました https://velog.io/@ikmy0ung/18.10-Dynamic-castingテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol