【问题标题】:How to compare class types in C++?如何比较 C++ 中的类类型?
【发布时间】:2015-02-10 12:49:35
【问题描述】:

假设我有:

class Base {/*...*/}
class Derived1: public Base {/*...*/}
class Derived2: public Base {/*...*/}

..我有:

class SomeClass {
public:
    template<typename DerivedType>
    DerivedType GetDerived();
private:
    vector<Base*> m_classes;
}

GetDerived() 函数中,我遍历 m_classes 向量,我想做类似的事情:

if(m_classes[i] == DerivedType) {
    return m_classes[i];
}

...假设我们知道 m_classes 中的一个对象将包含一个“DerivedType”对象。

示例:

m_classes[2] = Base* BasePtr = new Derived1;

.. 在这种情况下,我想像这样使用 GetDerived 函数:

GetDerived<Derived1>();

.. 这应该返回 m_classes[2]

我该怎么做?如何将基指针对象与派生类类型进行比较?更确切地说,GetDerived() 函数应该是什么样子?

【问题讨论】:

标签: c++ class types


【解决方案1】:

正如其他人所说,您应该看看这是否真的是解决您的问题的最佳方法,但 dynamic_cast 在 C++ 中可用。您必须使用 运行时类型标识 或 RTTI。

在编译器选项中打开它后,您可以在循环中执行此操作:

DerivedType* maybeDerived = dynamic_cast<DerivedType>(m_classes[i]);
if (maybeDerived)
     return maybeDerived;

【讨论】:

    【解决方案2】:

    当您需要区别对待时,将不同类的对象存储在同一个容器中是个坏主意。

    然而,这一次,C++ 提供了您正在寻找的东西。 dynamic_cast&lt;B&gt;(a) 将尝试将 a(无论它是什么)转换为类型 B。如果运行时类不匹配,它将返回nullptr

    你可以这样写GetDerived

    template <class Tsearched>
    Tsearched *GetDerived() {
        for(auto c : m_classes) {
            if(Tsearched *ptr = dynamic_cast<Tsearched*>(c))
                return ptr;
        }
        return nullptr;
    }
    

    或者,在标准算法的帮助下:

    template <class Tsearched>
    Tsearched *GetDerived() {
        auto found = std::find_if(m_classes.begin(), m_classes.end(), [](Base *ptr) {
            return dynamic_cast<Tsearched*>(ptr);
        });
        return found == m_classes.end() ? nullptr : static_cast<Tsearched*>(*found);
    }
    

    不过,让我再说一遍,这里存在设计问题。 RTTI(dynamic_cast 使用的)既不优雅也不快速。

    【讨论】:

    • A.您的代码可以简化为 find_if。 B. 您指的是这个案例还是泛指 RTTI?
    • @black RTTI 通常是最后尝试的方法,因为它是最佳选择的情况极为罕见。即便如此,它通常也只是解决设计问题的绷带。至于 find_if,我必须在取消引用之前检查迭代器,所以没有大小增益,但是为了完整性我会添加它。
    【解决方案3】:

    你可以使用dynamic_cast&lt;&gt;:

    template<typename DerivedType>
    std::vector<DerivedType*> GetDerived() { // note: return type changed
     std::vector<DerivedType*> result;
     for (DerivedType* at : this->m_classes) {
      if (DerivedType* as = dynamic_cast<DerivedType*>(at)) {
       result.push_back(as);
      }
     }
     return result;
    }
    

    dynamic_cast&lt;&gt; 需要带有运行时类型信息的 Base 类型(将存在于具有虚函数的类型上)。

    值得一提的是,有些人不喜欢dynamic_cast&lt;&gt;,一些约定/代码库禁止它。它是一种工具,可能会被滥用。

    【讨论】:

      【解决方案4】:

      通常这样做不是一个好主意。

      您可以使用dynamic_cast,如果对象不属于该类型,则返回nullptr,否则返回指向该类型的指针:

      if (nullptr != dynamic_cast<DerivedType*>(m_classes[i])) 
      { ... }
      

      【讨论】:

        【解决方案5】:

        您的示例语法无效。您不能在分配中间进行声明。然而,http://en.cppreference.com/w/cpp/types/is_base_of 之类的东西可以帮助在编译时识别派生。至于在运行时识别派生类型,您可以使用dynamic_cast,但理想的解决方案不需要这样做,这通常意味着您的对象或它们的使用方式存在潜在的设计缺陷。

        正如@PaulMcKenzie 所指出的,您可能应该问自己“为什么?”在担心如何做之前。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-26
          • 2012-09-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-06
          • 2014-08-19
          相关资源
          最近更新 更多