如何检查多态子类

时间:2017-10-23 08:59:33

标签: c++ templates polymorphism

我有一个类层次结构,其中I<T>O<T>是一个扩展B(常规类)的模板化类。 I通过指针聚合O,如下所示:

class B { ... };
template <class T>
class O : public B
{
    T getValue() { return value; }
private:
    T value;
}
template <class T>
class I : public B
{
    T getValue() { return ptr->getValue(); }
    void setPtr(O<T>* po) { ptr = po; }
private:
    O<T>* ptr;
}

上面的代码确实被简化为只显示它的骨头。尽管通过用户配置参数,“连接”IO仍会自动完成。因此,Singleton表存储了指向所有BI对象的多态O指针,并根据需要调用I::setPtr来执行链接。 但问题是,用户实际上可能会混淆和混淆IO对象的模板类型,例如用户可以要求将I<int>O<float>联系起来。 E.g:

O<int>* oi = new O<int>();
O<float>* of = new O<float>(); 
I<int> ii;
ii.setPtr(oi);  /* This is OK. */
O<int>* oi_wrong = static_cast<O<int>*>((B*)of);  /* This happens. */
ii.setPtr(oi_wrong); /* This is bad. */

为了防止这种行为,我在IO中都包含了一个存储typeid(T).name()的成员变量,因此可以检查模板参数是否实际相同。

有更好的方法吗?

编辑:这里有更好的方法进行投射吗?在这种情况下存储和使用多态指针不是一个好主意吗?

2 个答案:

答案 0 :(得分:1)

如果您的用户不想使用您的界面,那么您无能为力 - 您应该(合理地)设计代码而不假设您的用户将使用static_castreinterpret_cast自由地。

在您的情况下,我不会添加任何其他代码/支票。假设您的用户以合理的方式行事。

如果你真的想要,你可以使用assertdynamic_cast来检查传递的指针是否实际上是你在DEBUG构建中所期望的:

struct A { virtual ~A() { } };
struct B : A { };
struct C : A { };

void setPtr(A* po) 
{ 
    assert(dynamic_cast<C*>(po) != nullptr);
}

int main()
{
    B b;
    setPtr((C*)&b); // might trigger assertion
}

但我强烈建议不要这样做,因为这太过分了。

答案 1 :(得分:0)

如何为setPtr()使用友元函数,因此用户被迫输入I和O的拟合类型:

    class B { };
    template <typename T>
    class O : public B
    {
    public:
      T getValue() { return value; }
      void setPtr(I<T>& ref_i) { ref_i.ptr = this; };
    private:
      T value;
    };

    template <typename T>
    class I : public B
    {
    public:
      T getValue() { return ptr->getValue(); }
      friend void O::setPtr(I<T>& ref_i)
    private:
      O<T>* ptr;
    };


    int main()
    {
      O<int>* oi = new O<int>();
      O<float>* of = new O<float>();
      I<int> ii;
      of->setPtr(ii);  /* This fails. */
      O<int>* oi_wrong = static_cast<O<int>*>((B*)of);  /* This CAN                 happen. */
      oi->setPtr(ii); /* This is OK. */
    }