指向基类型的指针向量,查找存储在基类型中的给定派生类型的所有实例

时间:2014-04-27 15:50:39

标签: c++ boost base-class

假设您在库中有一个基类:

class A {};

和派生类

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

现在BC的实例存储在boost::shared_ptr<A>的std :: vector中:

std::vector<boost::shared_ptr<A> > A_vec;
A_vec.push_back(boost::shared_ptr<B>(new B()));
A_vec.push_back(boost::shared_ptr<C>(new C()));

添加BC的实例是由用户完成的,并且无法事先确定添加它们的顺序。

但是,在库内部,可能需要对BC执行特定操作,因此指向基类的指针需要转换为B并且C

我当然可以做&#34;试错&#34;转换,即尝试转换为BC(以及基类的任何其他衍生物),直到我找到一个不会抛出的转换。然而,这种方法看起来非常粗糙且容易出错,而且我正在寻找一种更优雅(也更好的)方式。

我正在寻找一种也适用于C ++ 98的解决方案,但可能涉及提升功能。

有什么想法吗?


修改

哦,谢谢你到目前为止的所有答案!

我想提供有关用例的更多详细信息。所有这些都发生在参数优化的背景下。

用户通过以下方式定义优化问题:

  • 指定参数,即它们的类型(例如&#34;约束双&#34;,&#34;约束整数&#34;,&#34;无约束双&#34;,&#34;布尔&#34;等)和初始值
  • 指定评估函数,该函数为给定参数集分配一个或多个评估(双精度值)

然后,不同的优化算法会对问题定义起作用,包括它们的参数。

对于常见情况,有许多预定义的参数对象,但用户也可以通过从我的一个基类派生来创建自己的参数对象。因此,从库的角度来看,除了参数对象需要符合给定(基类)API之外,我不能对参数对象有太多假设。

问题定义是一个用户定义的C ++类,派生自带有std :: vector接口的基类。用户添加他的(预定义的或本地生成的)参数对象并重载适应度函数。

可能会发生对参数对象的访问

  • 来自优化算法(通常是o.k.,甚至对于自行开发的参数对象,因为派生参数对象需要为其值提供访问函数)。
  • 来自用户提供的健身功能(通常是o.k.,因为用户知道在哪里可以找到集合中的哪个参数对象及其值可以轻松访问)

这很好用。

然而,可能会有特殊情况

  • 用户想要访问其本土参数类型的细节
  • 第三方提供了参数结构(这是一个开源库,其他人可能会为特定的优化问题添加代码)
  • 参数结构(即哪些参数在向量中的位置)可以作为优化问题的一部分进行修改 - &gt;示例:训练神经网络的架构

在这些情况下,有一个简单的方法可以访问基类型集合中给定派生类型的所有参数对象。

我已经有了模板化&#34; conversion_iterator&#34;。它迭代基础对象的向量,并跳过那些不符合所需目标类型的对象。但是,这是基于&#34;试验和错误&#34;转换(即我检查转换的智能指针是否为NULL),我发现它非常不优雅且容易出错。

我希望有更好的解决方案。

注意:优化库的目标是用例,其中给定参数集的评估步骤可能持续任意长(通常为几秒,可能是几小时或更长)。因此,访问参数类型的速度不是很大的问题。但稳定性和可维护性是......

5 个答案:

答案 0 :(得分:5)

没有比试图投射和看它是否成功更好的一般解决方案。你可以或者派生动态typeid并依次将它与所有类型进行比较,但这实际上是相同的工作量。

更重要的是,你需要这样做暗示了设计问题:基类的整个目的是能够像对待父母一样对待孩子。在某些情况下,这是必要的,在这种情况下,您可以使用visitor来分发它们。

答案 1 :(得分:2)

如果可能,请向班级A添加虚拟方法,以执行“BC上的具体操作”。

如果这不可能或不合理,请使用dynamic_cast的指针形式,因此不会涉及例外。

for (boost::shared_ptr<A> a : A_vec)
{
    if (B* b = dynamic_cast<B*>(a.get()))
    {
        b->do_something();
    }
    else if (C* c = dynamic_cast<C*>(a.get()))
    {
        something_else(*c);
    }
}

答案 2 :(得分:1)

  

添加B和C的实例是由用户完成的,并且无法预先确定添加它们的顺序。

好的,那么把它们放在两个不同的容器中?

std::vector<boost::shared_ptr<A> > A_vec;
std::vector<boost::shared_ptr<B> > B_vec;
std::vector<boost::shared_ptr<C> > C_vec;

void add(B * p)
{
    B_vec.push_back(boost::shared_ptr<B>(p));
    A_vec.push_back(b.back());
}

void add(C * p)
{
    C_vec.push_back(boost::shared_ptr<C>(p));
    A_vec.push_back(c.back());
}

然后你可以迭代Bs或Cs到你的心灵内容。

答案 3 :(得分:0)

我建议在基类中实现一个方法(例如TypeOf()),它将返回特定对象的类型。确保将该方法定义为虚拟和抽象,以便强制您在派生类型中实现。至于类型本身,您可以为每种类型(例如类)定义枚举。

enum class ClassType { ClassA, ClassB, ClassC };

答案 4 :(得分:0)

您可能会对此答案感兴趣: Generating an interface without virtual functions?

这显示了两种方法

  • 带有访客的变体
  • 单独的收藏,
正如其他人所建议的那样(弗雷德和康拉德,特别是)。后者对于迭代更有效,前者可能更加纯粹和可维护。它甚至可以更高效,具体取决于使用模式。