4

どちらかを優先するパフォーマンスまたは堅牢性の理由はありますか?

#include <iostream>
#include <typeinfo>

struct B
{
    virtual bool IsType(B const * b) const { return IsType2nd(b) && b->IsType2nd(this); }
    virtual bool IsType2nd(B const * b) const { return dynamic_cast<decltype(this)>(b) != nullptr; }
};

struct D0 : B
{
    virtual bool IsType(B const * b) const { return IsType2nd(b) && b->IsType2nd(this); }
    virtual bool IsType2nd(B const * b) const { return dynamic_cast<decltype(this)>(b) != nullptr; }
};

struct D1 : B
{
    virtual bool IsType(B const * b) const { return IsType2nd(b) && b->IsType2nd(this); }
    virtual bool IsType2nd(B const * b) const { return dynamic_cast<decltype(this)>(b) != nullptr; }
};

int main()
{
    using namespace std;
    B b, bb;
    D0 d0, dd0;
    D1 d1, dd1;

    cout << "type B  == type B  : " << (b.IsType(&bb)   ? "true " : "false") << endl;
    cout << "type B  == type D0 : " << (b.IsType(&dd0)  ? "true " : "false") << endl;
    cout << "type B  == type D1 : " << (b.IsType(&dd1)  ? "true " : "false") << endl;
    cout << "type D0 == type B  : " << (d0.IsType(&bb)  ? "true " : "false") << endl;
    cout << "type D0 == type D0 : " << (d0.IsType(&dd0) ? "true " : "false") << endl;
    cout << "type D0 == type D1 : " << (d0.IsType(&dd1) ? "true " : "false") << endl;
    cout << "type D1 == type B  : " << (d1.IsType(&bb)  ? "true " : "false") << endl;
    cout << "type D1 == type D0 : " << (d1.IsType(&dd0) ? "true " : "false") << endl;
    cout << "type D1 == type D1 : " << (d1.IsType(&dd1) ? "true " : "false") << endl;
    cout << endl;
    cout << "type B  == type B  : " << (typeid(b) == typeid(bb)   ? "true " : "false") << endl;
    cout << "type B  == type D0 : " << (typeid(b) == typeid(dd0)  ? "true " : "false") << endl;
    cout << "type B  == type D1 : " << (typeid(b) == typeid(dd1)  ? "true " : "false") << endl;
    cout << "type D0 == type B  : " << (typeid(d0) == typeid(&bb) ? "true " : "false") << endl;
    cout << "type D0 == type D0 : " << (typeid(d0) == typeid(dd0) ? "true " : "false") << endl;
    cout << "type D0 == type D1 : " << (typeid(d0) == typeid(dd1) ? "true " : "false") << endl;
    cout << "type D1 == type B  : " << (typeid(d1) == typeid(bb)  ? "true " : "false") << endl;
    cout << "type D1 == type D0 : " << (typeid(d1) == typeid(dd0) ? "true " : "false") << endl;
    cout << "type D1 == type D1 : " << (typeid(d1) == typeid(dd1) ? "true " : "false") << endl;
}

出力:

type B  == type B  : true 
type B  == type D0 : false
type B  == type D1 : false
type D0 == type B  : false
type D0 == type D0 : true 
type D0 == type D1 : false
type D1 == type B  : false
type D1 == type D0 : false
type D1 == type D1 : true 

type B  == type B  : true 
type B  == type D0 : false
type B  == type D1 : false
type D0 == type B  : false
type D0 == type D0 : true 
type D0 == type D1 : false
type D1 == type B  : false
type D1 == type D0 : false
type D1 == type D1 : true 
4

2 に答える 2

1

設計の観点からは、ダブル ディスパッチの方がはるかに柔軟です。

  • 現在、タイプ間の厳密な平等性を でチェックしていIsType2nd(b) && b->IsType2nd(this)ます。しかし、いつかはさらに派生させたいと思うかもしれません

  • しかし、ある日、D1 をさらに派生させたいと思うかもしれませんが、型を比較す​​るときに D1 オブジェクトであるかのように考えたいと思うかもしれません。このような特殊なケースは、二重発送で簡単に行えます。

この柔軟性には代償が伴います。アセンブラー コードは、vtable を介した 2 つの間接呼び出しと、動的キャストを使用します。

Sergey が指摘したように、直接の型情報は最適な設計ではありません。特殊なケースはあり得ず、常に厳密な型比較になります。

この柔軟性のなさには、コード生成の単純さという利点があります。コードは、vtable の開始時に動的な型情報を取得するだけで済みます (コンパイラは、コンパイル時に型がわかっているオブジェクトに対して、このフェッチを簡単に最適化できます。

好奇心のために、ここでいくつかのコードが生成されます。 typeid はコンパイル時に最適化されますが、二重ディスパッチは依然として間接呼び出しに依存しています。

于 2016-02-12T21:40:02.690 に答える
0

typeidコメントに記載されているように、使用も依存もしない別の可能な解決策に従いますdynamic_cast

ファミリタイプを簡単に定義する方法を示すために、いくつかの例を追加しました(例として、ここではD1D1Bisが実際には異なるタイプであっても、同じファミリ タイプとして表示されます)。
とにかく、それが望ましい機能かどうかはわかりません...

興味を持っていただければ幸いです。

#include<iostream>

struct BB {
    virtual unsigned int GetType() = 0;

    bool IsType(BB *other) {
        return GetType() == other->GetType();
    }

protected:
    static unsigned int bbType;
};

unsigned int BB::bbType = 0;

struct B: public BB {
    unsigned int GetType() override {
        static unsigned int bType = BB::bbType++;
        return bType;
    }
};

struct D0: public B {
    unsigned int GetType() override {
        static unsigned int d0Type = BB::bbType++;
        return d0Type;
    }
};

struct D1: public B {
    unsigned int GetType() override {
        static unsigned int d1Type = BB::bbType++;
        return d1Type;
    }
};

struct D1Bis: public D1 { };

int main() {
    using namespace std;
    B b, bb;
    D0 d0, dd0;
    D1 d1, dd1;
    D1Bis d1Bis;

    cout << "type B  == type B  : " << (b.IsType(&bb)   ? "true " : "false") << endl;
    cout << "type B  == type D0 : " << (b.IsType(&dd0)  ? "true " : "false") << endl;
    cout << "type B  == type D1 : " << (b.IsType(&dd1)  ? "true " : "false") << endl;
    cout << "type B  == type D1BIS : " << (b.IsType(&d1Bis)  ? "true " : "false") << endl;
    cout << "type D0 == type B  : " << (d0.IsType(&bb)  ? "true " : "false") << endl;
    cout << "type D0 == type D0 : " << (d0.IsType(&dd0) ? "true " : "false") << endl;
    cout << "type D0 == type D1 : " << (d0.IsType(&dd1) ? "true " : "false") << endl;
    cout << "type D0 == type D1BIS : " << (d0.IsType(&d1Bis) ? "true " : "false") << endl;
    cout << "type D1 == type B  : " << (d1.IsType(&bb)  ? "true " : "false") << endl;
    cout << "type D1 == type D0 : " << (d1.IsType(&dd0) ? "true " : "false") << endl;
    cout << "type D1 == type D1 : " << (d1.IsType(&dd1) ? "true " : "false") << endl;
    cout << "type D1 == type D1Bis : " << (d1.IsType(&d1Bis) ? "true " : "false") << endl;
}
于 2016-02-14T00:05:55.713 に答える