【问题标题】:Best way to determine the type of an object at runtime在运行时确定对象类型的最佳方法
【发布时间】:2015-11-08 07:29:08
【问题描述】:

所以我要做的是实现消息模式。据我了解,用户将根据我输入的消息类型而不是执行操作的消息类型采取行动。因此,这就是我的处理方式:

我想获取对象的数据类型,以便执行 switch 语句,但我不确定从哪里开始。

我浏览了谷歌并做了一些研究,但没有一个成功。这是我尝试过的:

  • Decltype : 甚至不接近我想要的
  • typeof : 我不太清楚怎么用
  • 动态投射:不接近我想要的

基本上,我最后想要的是这样的:

switch (typeof(a)) {
    class_a : //do something
    class_b : //do something
}

if 语句对我来说也是一样的。谁能帮我吗?我更喜欢使用标准库。

【问题讨论】:

  • boost::variant
  • @user1034749 有没有办法在不使用外部库的情况下做到这一点?
  • 这可能是XY problem。你想达到什么目的?
  • @bolov 我正在尝试实现消息模式。据我所知,它将基于对象来定义我输入的信息并据此采取行动。
  • 你可以在c++11中使用union来管理不平凡的对象,但实际上你编写的代码与boost::variantboost::any几乎相同

标签: c++ c++11 design-patterns rtti


【解决方案1】:

在标准 C++ 中没有 typeof(尽管有一个 GCC 扩展名)。您正在寻找 typeid 运算符。这将返回对包含对象的运行时类型信息 (RTTI) 的 static const std::type_info 实例的引用。您可以将结果与您感兴趣的各个类的typeids 进行比较。

作为一个简单的例子(see it run at ideone):

#include <iostream>
#include <typeinfo>

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

class B: public A {};
class C: public A {};


int main() {
    const A& a = C{};

    const auto& id = typeid(a);

    if(id == typeid(B)) {
        std::cout << "Got a B." << std::endl;
    }
    else if(id == typeid(C)) {
        std::cout << "It's a C!" << std::endl;
    }

    return 0;
}

(请注意,您不能使用switch,因为对象不是整数。)此示例将打印It's a C!

请注意,一般来说,使用 RTTI 不应该是您的第一反应(请注意,尤其是如果您来自 Java 等语言,其中动态类型(及其相关的速度影响)被认为是理所当然的)。

与其他面向对象的范例相比,RTTI 相对较慢,甚至是动态调度(virtual 函数)。如果您尝试实现消息模式,请考虑将显式值作为消息传递,而不是将您的其他对象硬塞到模式中并招致 RTTI 的昂贵开销。

【讨论】:

  • 我有两个问题: 1. 如果我坚持这个,基本上我必须存储一个我想要比较的类型的对象,对吧?它不能直接与类(蓝图)本身进行比较吗? 2. 将显式值作为消息传递是什么意思?
  • 如果需要,您可以直接传递对std::type_info 结构的引用;您不必实例化对象(例如,请参阅我在哪里做 typeid(B))。如果我理解正确,您只是试图在组件之间发送消息,然后根据消息执行不同的操作?通常,您可以简单地发送enum 的实例(显式值),这与您在 C++ 中获得的速度一样快。拿到typeid 之后,你对这个对象做了什么?
  • 所以在我目前的架构中,我有 3 种不同类型的消息和 1 个用户。每条消息都有一个作为 BaseMessage 的基类。我使用 factoryPattern 创建要传递给用户的消息。并且根据消息的类型,我会让用户采取不同的行动。但是我刚刚想到了一种摆脱困境的方法,在每个子类中创建一个新变量并在其中放入一个枚举。然后用户可以轻松检查枚举以获取消息类型:D
【解决方案2】:

动态投射:不接近我想要的

你拿错了。动态演员当然可以做你想做的事。

if (dynamic_cast<c1*>(a)) { ... }
else if (dynamic_cast<c2*>(a)) { ... }

*a 的静态类型必须是多态的。同样的事情适用于参考。如果您按值传递它,它不会也不能工作。

然而,这是一种危险且容易出错的实现方式。如果您想为 M 个接收者类型实现 N 个消息类型,并且所有 M×N 操作都可能不同,请考虑使用访问者模式,尤其是它的非循环实现。

【讨论】:

  • 嗨。我完全意识到虚拟方法的这种使用。正如我在文章开头提到的那样,我正在尝试实现消息模式,它要求用户知道我传入的对象的类型。所以谢谢:)
  • 删除基本建议,添加高级建议。
猜你喜欢
  • 2012-04-05
  • 2015-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
相关资源
最近更新 更多