2

reinterpret_cast実際には派生インスタンスポインタであるベースポインタからキャストするためにどのシナリオを使用できますか?(ポリモーフィズムを介して)。

継承が多形である場合、静的キャストは機能しません。

私はこの些細なシナリオを検討しました:

class A
{
public:
    virtual void Hello()
    {
        cout<<" A ";
    }
    virtual int GetType() { return 1; }
};

class B: public A
{
public:
    void Hello()
    {
        cout<< " B ";
    }
    void Do()
    {
        cout << " Another method of B";
    }
    int GetType() { return 2;}
};

/// ... sample/test code
A* a1 = new A();
A* b1 = new B();
A* a2;
B* b2;

if (a1->GetType() == 1)
{
    a2 = a1;
    a2->Hello();
}
else
if (a1->GetType() == 2)
{
    b2 = reinterpret_cast<B*>(a1);
    b2->Do();
    b2->Hello();
}

非常に素朴な「疑似型識別方法」GetType()に注意してください。私はそれらを変換できるかどうかを判断していました。そのような目的で、dynamic_castsを回避するためにreinterpret_castsを使用するのはまったく間違っていますか?(つまり、本質的に危険なパラノイックな設計ですか?)柔軟性が低く、望ましくない問題が発生する可能性がありますか?通常の動的キャストを実行する方が安全でパフォーマンスコストが少ない価値がありますか?多重継承および/または仮想継承は、ポリモーフィック/動的キャストを除く他のキャスト操作を台無しにすることを知っています)。

4

6 に答える 6

6

reinterpret_cast安全にダウンキャストするために使用することはできません。しかし、あなたは使うことができます

  • static_cast、オブジェクトの動的タイプが(おそらくから派生した)キャストダウンしたものであることがわかっている場合、および

  • dynamic_cast、参照またはポインタの、静的に既知のクラスが多形である場合。

反対の方向では、アップキャストの場合、アクセスできないベースにキャストするためにCスタイルのキャストを使用できます(ただし、使用しないでください)。標準で特別にサポートされています。しかし、私はそれを使う機会を見つけたことがありません。

于 2012-11-16T13:33:03.527 に答える
5

最初の文に答えるだけです:決して。

ベースポインタをより派生したポインタに静的に変換する唯一の有効な方法は、を使用することです。static_castこれは、ベースが非仮想である場合にのみ機能します。

Base * b = &derived;                       // implicit Derived * => Base *

Derived * p = static_cast<Derived *>(b);   // OK, I know what *b really is

静的キャストは、暗黙的な変換の反対と考える必要があります。

Areinterpret_castは完全に間違っています。(一般的に受け入れられる再解釈キャストは、I / Oの目的でポインターをcharすることだけです。)

(仮想ベースへのポインターがある場合、を使用する以外に選択肢はありませんがdynamic_cast、それはもちろん、その場合、ベースサブオブジェクトは実行時にのみ決定されるためです。)

于 2012-11-16T13:31:39.000 に答える
1

可能な場合はreinterpret_castを使用しないでください。reinterpret_castを使用する主な理由は、Cで記述されたレガシーコードを処理する場合です。それ以外の場合は、static_castとdynamic_castを使用する必要があります。設計でreinterpret_castを使用する必要がある場合は、これをヒントとして使用できます。あなたのデザインは最適ではないかもしれません。

static_castは、常に成功することが確実である限り、ポリモーフィック型に使用できます。それ以外の場合は、dynamic_castを使用する必要があります。

于 2012-11-16T13:32:22.093 に答える
0

BではないものでBメソッド関数を呼び出すことは危険です。質問のタイトルは「安全な」代替手段であり、コードは安全ではありません。

ほとんどの場合、dynamic_castの使用は不適切であり、設計が不十分であることを示しています。

特にバージョン管理されたプラグインを使用する場合は、便利な場合があります。プラグインをロードして、新しい機能をサポートする場合とサポートしない場合があるオブジェクトを取得し、サポートしていることがわかっているインターフェイス(基本クラス)を新しいバージョン(それから派生したもの)に動的にキャストできます。それが機能する場合は、新しい機能を使用できます。そうでない場合は、この機能を無効にするか、古い方法を使用する必要があります。

時々、あなたはこの種のことをするためにダブルディスパッチを使うことができます。

于 2012-11-16T13:46:56.440 に答える
0

dynamic_castこの場合、なぜを避けるのですか?キャストを実行する前に仮想メンバー関数を呼び出す必要があるため、を使用する場合よりも(パフォーマンスの点で)多くの費用がかかる可能性がありますdynamic_cast

于 2012-11-16T13:30:08.760 に答える
0

私が知っているdynamic_castの唯一の「安全な」代替手段は、VisitorPatternを使用することです。例(コンパイラエクスプローラ):

class A;
class B;

class TypeVisitor {
 public:
    virtual void VisitA(A&) = 0;
    virtual void VisitB(B&) = 0;
    virtual ~TypeVisitor() = default;
};

class A
{
public:
    virtual void Hello()
    {
        cout<<" A\n";
    }

    virtual int GetType() { return 1; }

    virtual void Accept(TypeVisitor& visitor) {
        visitor.VisitA(*this);
    }
};

class B: public A
{
public:
    void Hello() override
    {
        cout<< " B\n";
    }

    void Do()
    {
        cout << " Another method of B\n";
    }

    int GetType() override { return 2; }

    void Accept(TypeVisitor& visitor) override {
        visitor.VisitB(*this);
    }
};

class PrintHelloVisitor : public TypeVisitor {
 public:
    virtual void VisitA(A& a) override {
        a.Hello();
    }

    virtual void VisitB(B& b)  override {
        b.Hello();
        b.Do(); // calling also the method that is not virtual
    }

    virtual ~PrintHelloVisitor() = default;
};

int main() {
    PrintHelloVisitor print_visitor;

    unique_ptr<A> a1 = make_unique<A>();
    a1->Accept(print_visitor);

    unique_ptr<A> b1 = make_unique<B>();
    b1->Accept(print_visitor);

    unique_ptr<B> b2 = make_unique<B>();
    b2->Accept(print_visitor);
}

プリント:

 A
 B
 Another method of B
 B
 Another method of B
于 2020-04-01T21:16:57.540 に答える