假设我有一堆水果:
class Fruit { ... };
class Apple : public Fruit { ... };
class Orange: public Fruit { ... };
以及一些对所述水果进行操作的多态函数:
void Eat(Fruit* f, Pesticide* p) { ... }
void Eat(Apple* f, Pesticide* p) { ingest(f,p); }
void Eat(Orange* f, Pesticide* p) { peel(f,p); ingest(f,p); }
好的,等等。停在那儿。请注意,任何理智的人都会将 Eat() 设为 Fruit 类的虚拟成员函数。但这不是一个选择,因为我不是一个理智的人。另外,我不想在我的水果类的头文件中使用 Pesticide*。
遗憾的是,接下来我想做的正是成员函数和动态绑定(bind)所允许的:
typedef list<Fruit*> Fruits;
Fruits fs;
...
for(Fruits::iterator i=fs.begin(), e=fs.end(); i!=e; ++i)
Eat(*i);
显然,这里的问题是我们传递给 Eat() 的指针将是 Fruit*,而不是 Apple* 或 Orange*,因此什么都不会被吃掉,我们都会非常饿。
所以我真正希望能够做的不是这个:
Eat(*i);
这是:
Eat(MAGIC_CAST_TO_MOST_DERIVED_CLASS(*i));
但据我所知,这样的魔法并不存在,除了可能以充满对 dynamic_cast 调用的大型讨厌 if 语句的形式存在。
那么是否存在一些我不知道的运行时魔法?或者我应该实现和维护一个充满 dynamic_casts 的讨厌的 if 语句吗?还是我应该接受它,不再考虑如何在 Ruby 中实现它,让一点 Pesticide 进入我的水果头?
更新:与其使用简单的 Eat 函数和 Pesticide 做作,不如假设我只是不想将 Eat 放入水果中,因为它没有意义。一种会自己吃的水果?噗。相反,我需要一个带有 Eat 函数的 Eater 类,其中包含用于吃每种水果的不同代码,以及一些默认代码以防吃者无法识别水果:
class Eater
{
public:
void Eat(Apple* f) { wash(); nom(); }
void Eat(Orange* f) { peel(); nom(); }
void Eat(Fruit* f) { nibble(); }
};
...
Eater me;
for(Fruits::iterator i=fs.begin(), e=fs.end(); i!=e; ++i)
me.Eat(*i); //me tarzan! me eat!
但同样,这不起作用,C++ 中的直接解决方案似乎是对 dynamic_cast 的一堆调用。
但是,正如其中一个答案所暗示的那样,可能还有另一个聪明的解决方案。如果 Fruits 通过 MustPeel() 和 MustWash() 等函数展示对食用者重要的品质会怎样?然后你可以用一个 Eat() 函数来解决问题......
更新:Daniel Newby 指出,使用 Visitor 也可以解决所提出的问题……但这需要一些语义倒立(Fruit::use 或 Fruit::beEaten?)。
虽然我愿意接受几个答案,但我认为 psmears 的答案对于 future 的读者来说实际上是最好的答案。谢谢大家。
最佳答案
您需要重新设计。即,做您似乎在避免的一切(出于什么原因,谁知道呢。)
多态行为需要多态函数。这意味着一个 virtual 函数。 (或者你的 dynamic_cast 阶梯,这完全违背了目的......)
// fruit.h
class Pesticide; // you don't need a complete type
struct Fruit
{
virtual void Eat(Pesticide*) = 0;
};
// apple.h
class Apple : public Fruit
{
void Eat(Pesticide* p) { ... }
};
// orange.h
class Orange : public Fruit
{
void Eat(Pesticide* p) { ... }
};
如果您还想要一个免费功能*:
void Eat(Fruit* f, Pesticide* p) { f->Eat(p); }
*请注意,您的帖子已经表明设计不当;即第一个 Eat 函数:
void Eat(Fruit* f, Pesticide* p) { }
什么时候对水果什么都不做等同于吃水果?纯虚函数是更好的接口(interface)选择。
关于c++ - 苹果、橘子和指向最派生的 c++ 类的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3049404/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow
我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下
如何将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.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内