草庐IT

c++ - 将相同共享指针的拷贝存储在不同的 vector 中是一种好习惯吗?

coder 2023-11-17 原文

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

class BaseObject
{
  virtual void commonMethod();
}

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

Class DerivedObject2 : public BaseObject
{
  void commonMethod();
}

MyClass 中有两个 vector 有什么缺点,一个存储 DerivedObject1DerivedObject2 的所有指针,另一个 vector 仅存储 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();
    }
  }
}

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

最佳答案

有趣的问题。 我们在维护不知道是谁写的遗留代码时,有时会遇到这样的情况。

Are there any disadvantages of having two vectors in MyClass … ?

我认为没有机械(或性能)缺点。 如果我们在发布截止日期前苦苦挣扎,我们别无选择,只能选择这种简单的方式。 但是,将相同的 vector 存储两次实际上会降低可维护性,我们应该考虑在未来改进它。


  • std::dynamic_pointer_cast(或 boost::dynamic_pointer_cast)[Demo]

如果你需要dynamic_pointer_cast来实现像@Caleth这样的功能的push_back/remove, 从一开始就删除 only_derived1 并不情愿地在 doSomethingForDerivedObject1() 中只应用一个 dynamic_pointer_cast 怎么样? 它将使 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();
        }
    }
}

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

void DerivedObject2::additionalMethod()
{ 
  /* nothing to do */
}

然后您可以再次删除 only_derived1。 在此方法中,仅当定义了 DerivedObject3 时,您才必须实现 DerivedObject3::additionalMethod()

但是,虽然这取决于你的构造函数或setter代码,如果也会出现下面的情况

everything;    ->derived2
only_derived1; ->derived1

这个方法还是不够的。


理想情况下,我们不应该使用公共(public)继承来实现“IS-ALMOST-A”关系中的对象,如 Herb Sutter 所说。 BaseObjectDerivedObject1DerivedObject2 之间的关系如下所示。 由于我不知道您的应用程序的完整代码,所以我可能是错的,但考虑将 DerivedObject1::additionalMethod() 提取为另一个类或函数指针并将其 vector 放入 MyClass 中是值得的作为私有(private)成员(member)。

关于c++ - 将相同共享指针的拷贝存储在不同的 vector 中是一种好习惯吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52627324/

有关c++ - 将相同共享指针的拷贝存储在不同的 vector 中是一种好习惯吗?的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  4. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  7. ruby -::在 Ruby 语法中是什么意思? - 2

    这个问题在这里已经有了答案:WhatisRuby'sdouble-colon`::`?(12个答案)关闭8年前。什么是::?@song||=::TwelveDaysSong.new

  8. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

随机推荐