C++ C++;类型比较:typeid与双分派动态\u cast

C++ C++;类型比较:typeid与双分派动态\u cast,c++,dynamic-cast,typeid,double-dispatch,C++,Dynamic Cast,Typeid,Double Dispatch,是否有任何性能或健壮性方面的原因可以选择其中一种 #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 dynam

是否有任何性能或健壮性方面的原因可以选择其中一种

#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;
}

从设计角度来看,双重分派要灵活得多:

  • 当前,您使用
    IsType2nd(b)和&b->IsType2nd(this)
    检查类型之间的严格平等性。但可能在某个时候你想进一步推导

  • 虽然有一天你可能想进一步推导D1,但仍然想把它看作是比较类型时D1对象所在的地方。这种特殊情况很容易通过双重分派完成

这种灵活性是有代价的:汇编代码将通过vtable使用2个间接调用,外加一个动态强制转换

正如Sergey指出的那样,直接类型信息并不是最好的设计:它将始终是严格的类型比较,不可能有特殊情况

这种不灵活的特性带来了代码生成的简单性:代码只需在vtable开始时获取动态类型信息(并且编译器可以轻松地为编译时已知类型的对象优化此提取)


出于好奇,这里:typeid在编译时被优化了,而double dispatch仍然依赖于间接调用。

如注释中所述,它遵循另一种可能的解决方案,既不使用
typeid
,也不依赖
动态转换

我添加了两个附加示例,以演示如何轻松定义族类型(例如,
D1
D1Bis
显示为属于相同的族类型,即使它们实际上是不同的类型)。
无论如何,我不确定这是不是一个理想的功能

希望你感兴趣

#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;
}
#包括
结构BB{
虚拟无符号int GetType()=0;
bool IsType(BB*其他){
返回GetType()==其他->GetType();
}
受保护的:
静态无符号整型;
};
无符号整型BB::bbType=0;
结构B:公共BB{
无符号int GetType()重写{
静态无符号int bType=BB::bbType++;
返回b类型;
}
};
结构D0:公共B{
无符号int GetType()重写{
静态无符号int d0Type=BB::bbType++;
返回类型;
}
};
结构D1:公共B{
无符号int GetType()重写{
静态无符号int d1Type=BB::bbType++;
返回类型;
}
};
结构D1Bis:公共D1{};
int main(){
使用名称空间std;
B,bb;
D0-D0,dd0;
D1,dd1;
D1Bis D1Bis;

根据我的经验,任何试图找出多态类的实际类型的尝试都表明存在设计缺陷。@SergeyA同意。我继承了到处都使用类型切换的代码,并试图对其进行改进。您是否也接受第三个选项,或者您只对上面两个选项感兴趣?@skypjack,第三个选项是什么?@ThomasMcLeod抱歉,我如果我迟到了,我一直很忙。第三个选项取决于您的需求。它是否像示例中那样是一个1级的层次结构?您能否在实际问题中实例化
B
?这基本上是C语言时代常见的类型枚举解决方案。好的,这在今天仍然被使用,通常与
CRTP
习惯用法一起,以给出一个类型到派生类(例如,
entityx
执行类似操作),但它不适合具有多个级别的层次结构,因此…我尝试调整解决方案以适应您的问题。CRTP不需要,因为您可以使用模板类型推断来发现基类的模板参数。通常并不意味着必须。总之,我谈到了第三个可行的选项,这一个可行,感觉不错免费不使用它。:-)
#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;
}