1

所以我正在做一个个人项目(试图在 C++ 上做得更好),我正在努力让它工作:

我有一个带有纯虚函数 interactWith(A* target); 的 ABC 类 A

然后我有两个派生类,B类和C类。

但是,B 类必须与 C 类交互,而不是与另一个 B 类交互

我在 ABC 中找到了一种使用 if/else 和虚拟 getType() 的方法,但我很好奇是否有更优雅的方法,或者我是否只是在做一些非常愚蠢的事情,以及我是否正在做某事愚蠢的(这很有可能),我会从哪里开始寻找更好的解决方案(即更合适的设计模式)

请注意:我没有使用 boost,我现在宁愿避免它,等我真正擅长编程时开始学习它

欢迎您提供任何帮助。谢谢,麻烦您了

我应该注意的一点:B 类和 C 类将(应该)仅通过 A* 可见

4

4 回答 4

2

您尝试实现的功能称为双重分派:一个对两个对象表现为虚拟的函数。

有几种方法可以实现它,其中一种更常见的是使用访问者模式

Scott Meyers 有一个关于实现双重调度的优秀章节(在他的“More Effective C++”一书中的第 31 条)。他从访问者模式的讨论开始,然后继续使用RTTI实现一个非常好的实现。

于 2012-06-07T00:32:20.967 回答
2

您几乎从不想使用类型切换。动态转换稍微好一点,但如果可能的话仍然要避免。

一个更好的选择是扭转局面,这样您就可以再次使用虚拟调度机制,通常称为“双重调度”或“模拟多方法”。它看起来像这样:

struct B;

struct A { 
  virtual void interactWith(A* target); 
  virtual void interactWithB(B* target);
};

struct B : A {
  virtual void interactWith(A* target) {
    target->interactWithB(this);
  }
  virtual void interactWithB(B* lhs) {
    // B vs. B stuff goes here, but with lhs and this in place of this and target
  }
};

struct C : A {
  virtual void interactWith(A* target) {
    // C vs. anything stuff goes here
  }
  virtual void interactWithB(B* lhs) {
    // B vs. C stuff goes here, again backward
  }
};
于 2012-06-07T00:32:56.460 回答
0

使用 dynamic_cast

C* cTarget = dynamic_cast<C*>(target);
if(cTarget == NULL)
{
    //cTarget is not a C
}
else if(cTarget)
{
    //cTarget is a C
}

dynamic_cast 做了一些花哨的东西(我不确定它做了什么)来确保强制转换是有效的,如果不是,它返回 NULL。

于 2012-06-07T00:28:07.130 回答
0

理想情况下,封装与 B 和 C 交互时需要在 B 和 C 之间有所不同的行为,并将其放入您调用的另一个虚拟方法中target——然后在 B 和 C 中适当地对该方法进行不同的实现。

如果上述内容过于混乱和分散,则表明您选择了错误的抽象作为您的对象。您最好放弃 A/B/C 类层次结构并将您的程序划分为不同的层次结构,但如果没有更具体的描述您正在尝试做什么,这是不可能的。过早的抽象(连同过早的优化)是没有经验的程序员经常犯的关键错误之一。

于 2012-06-07T00:35:28.347 回答