将相同的共享指针的副本存储在不同的向量中是一种好的做法吗?

Ena*_*aid 7 c++ shared-ptr c++03

我有一个基类,BaseObject和两个派生类DerivedObject1DerivedObject2.他们有共同的行为和方法,但DerivedObject1还有一个额外的方法.我的主类MyClass存储(in std::vector)boost::shared_ptr这些类的实例.MyClass需要调用commonMethod()所有BaseObject,有时需要调用additionalMethod()所有DerivedObject1.

class BaseObject
{
  virtual void commonMethod();
}

Class DerivedObject1 : public BaseObject
{
  void commonMethod();
  void additionalMethod();
}

Class DerivedObject2 : public BaseObject
{
  void commonMethod();
}
Run Code Online (Sandbox Code Playgroud)

有两个向量的缺点MyClass,一个存储所有指针的DerivedObject1DerivedObject2,另一个向量只存储指针DerivedObject1?意思是我会有DerivedObject1两次所有的指针.但我认为对不同方法的要求至少是明确的.

class MyClass
{
  typedef std::vector<std::shared_ptr<BaseObject>> BaseObjectVector;
  typedef std::vector<std::shared_ptr<DerivedObject1>> DerivedObject1Vector;
  BaseObjectVector everything;
  DerivedObject1Vector only_derived1;

  void doSomething()
  {
    for (BaseObjectVector::iterator iter = everything.begin(); iter != everything.end(); ++iter)
    {
      (*iter)->commonMethod();
    }
  }

  void doSomethingForDerivedObject1()
  {
    for (DerivedObject1Vector::iterator iter = only_derived1.begin(); iter != only_derived1.end(); ++iter)
    {
      (*iter)->additionalMethod();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以想到其他方法,主要有一个向量DerivedObject1和一个向量DerivedObject2,但要调用commonMethod(),我将不得不迭代两个向量.我的原始解决方案对我来说似乎是最好的,除了一些指针存储两次.这有什么缺点?

Hir*_*oki 6

有趣的问题.我们有时会遇到维护遗留代码的情况,我们不知道谁编写了这些代码.

在MyClass中有两个向量有什么缺点吗?

我认为没有机械(或性能)缺点. 如果我们努力满足发布截止日期,我们别无选择,只能选择这么简单的方式.但是,两次存储相同的向量实际上会降低可维护性,我们应该考虑在将来对其进行改进.


  • std :: dynamic_pointer_cast(或boost :: dynamic_pointer_cast)[演示]

如果你需要dynamic_pointer_cast实现像@Caleth 's push_back/ 这样的函数remove,那么如何从一开始only_derived1就删除和不情愿地应用一个dynamic_pointer_castin doSomethingForDerivedObject1()如下?它将使MyClass更简单.如果将来定义DerivedObject3,则所需的修改不会很复杂.

void MyClass::doSomethingForDerivedObject1()
{
    for (const auto& obj_i : everything)
    {
      if (auto derived1 = std::dynamic_pointer_cast<DerivedObject1>(obj_i))
        {
           derived1->additionalMethod();
        }
    }
}

void MyClass::doSomethingForDerivedObject3()
{
    for (const auto& obj_i : everything)
    {
      if (auto derived3 = std::dynamic_pointer_cast<DerivedObject3>(obj_i))
        {
           derived3->additionalMethod();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

声明虚函数BaseObject::additionalMethod()并实现

void DerivedObject2::additionalMethod()
{ 
  /* nothing to do */
}
Run Code Online (Sandbox Code Playgroud)

然后你可以再次删除only_derived1.在此方法中,DerivedObject3::additionalMethod()只有在定义了DerivedObject3时才必须实现.

但是,虽然它取决于您的构造函数或setter代码,但是如果还会发生以下情况

everything;    ->derived2
only_derived1; ->derived1
Run Code Online (Sandbox Code Playgroud)

这种方法还不够.


理想情况下,我们不应该用公有继承来实现中的对象"IS-ALMOST-A"关系,如香草萨特说,之间的关系BaseObject,DerivedObject1以及DerivedObject2看起来像这一个.因为我不知道你的应用程序的整个代码可能是我错误,但值得考虑提取DerivedObject1::additionalMethod()为另一个类或函数指针,并将其向量作为私有成员放在MyClass中.