【问题标题】:Get object's type from pointer to base class at runtime在运行时从指向基类的指针获取对象的类型
【发布时间】:2017-01-01 12:02:15
【问题描述】:

我正在使用一个类库,其中所有类都直接或间接地从基类Base 派生并具有名称。该库提供了一种按名称搜索对象的工具,该名称将返回 Base*。

有没有什么方法可以找到返回对象的类型,而无需像下面的示例中那样使用dynamic_casts 检查所有可能性?如果可能的话,我想避免这种情况,因为派生类有模板参数,这有很多可能性。

如果我至少能够在不知道模板类型的情况下找出类类型(T1 或T2,在下面的示例中),那也很好。做类似dynamic_cast<T1<i_dont_care>*>的事情。

#include <iostream>

using namespace std;

class Base {
public:
    virtual ~Base() {}
};

template <typename T> class T1 : public Base {};
template <typename T> class T2 : public Base {};

Base *find_by_name() {
    return new T2<int>();
}

int main() {
    Base *b = find_by_name();

    if (T1<int> *p = dynamic_cast<T1<int>*>(b)) {
        cout << "T1<int>" << endl;
        // do something meaningful with p
    } else if (T1<double> *p = dynamic_cast<T1<double>*>(b))
        cout << "T1<double>" << endl;
    else if (T2<int> *p = dynamic_cast<T2<int>*>(b))
        cout << "T2<int>" << endl;
    else if (T2<double> *p = dynamic_cast<T2<double>*>(b))
        cout << "T2<double>" << endl;
    else
        cout << "unknown" << endl;

    delete b;

    return 0;
}

请注意,上面的示例是简化的,即。在每个if 中,我都会对p 做一些有意义的事情。

我确实从一开始就意识到这是一个糟糕的设计,但是我被这个库困住了,我也没有办法改变它的实现。

【问题讨论】:

  • 如果需要此功能,那么b 应该有一个成员来执行此操作。您也可以尝试检查typeid(*b).name()。
  • 你的p都是多余的,写if ( dynamic_cast&lt;T1&lt;int&gt;*&gt;(b) )
  • Base真的没有其他成员了吗?这似乎是图书馆应该提供的那种功能。使用普通指针只能做这么多。
  • @M.M:我得考虑一下typeid 的想法,谢谢。关于多余的ps,看来我的例子有点过于简单了:)。
  • 返回 Base*... 伙计,我以为我们已经解决了该死的赛昂人。

标签: c++ dynamic rtti


【解决方案1】:

有类似typeidhttp://en.cppreference.com/w/cpp/language/typeid 的东西,应用于多态表达式将在运行时评估其类型表示。

以下 wiki 示例:https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast

#include <iostream> 
#include <typeinfo>    // for 'typeid'

class Person {
public:
   virtual ~Person() {}
};

class Employee : public Person {
};

int main() 
{
    Person person;
    Employee employee;
    Person* ptr = &employee;
    Person& ref = employee;
    // The string returned by typeid::name is implementation-defined

    // Person (statically known at compile-time)
    std::cout << typeid(person).name() << std::endl;   

    // Employee (statically known at compile-time)
    std::cout << typeid(employee).name() << std::endl; 

    // Person* (statically known at compile-time)
    std::cout << typeid(ptr).name() << std::endl;      

    /* Employee (looked up dynamically at run-time
     * because it is the dereference of a
     * pointer to a polymorphic class) */
    std::cout << typeid(*ptr).name() << std::endl;     

    // Employee (references can also be polymorphic)        
    std::cout << typeid(ref).name() << std::endl;      
}

【讨论】:

    【解决方案2】:

    有一个typeid操作符,它返回一个std::type_info的实例,你可以通过它获取类型的名称。

    但不确定这是否会对您有所帮助。首先,返回的名称不能保证在不同的实现中是相同的。第二 - 一旦你有了名字,你会怎么做?您可能会将其与您的预定义名称进行比较,但这可能比一堆 dynamic_cast 慢。

    如果Base 类中没有内置类型支持或没有新的层次结构中间层,dynamic_cast 是您的最佳选择。实际上它会非常快(通常只是一个比较指令)。

    我的意思是中间层:

    class Base {
    public:
        virtual ~Base() {}
    };
    
    class T1Base : public Base {};
    class T2Base : public Base {};
    
    template <typename T> class T1 : public T1Base {};
    template <typename T> class T2 : public T2Base {};
    
    int main() {
        Base *b = find_by_name();
    
        if (dynamic_cast<T1Base*>(b))
            cout << "T1" << endl;
        else if (dynamic_cast<T2Base*>(b))
            cout << "T2" << endl;
        else
            cout << "unknown" << endl;
    
        delete b;
    
        return 0;
    }
    

    【讨论】:

    • 接受这个答案,因为它指出了最好的选择,即使在这种特殊情况下,这些似乎都没有真正帮助我。大量的dynamic_casts 它是......
    • 这不是答案,这是已知类类型之间的情况。
    猜你喜欢
    • 2014-06-16
    • 2017-06-29
    • 2023-02-09
    • 2021-07-02
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    相关资源
    最近更新 更多