2

我最近遇到了一个烦人的问题,我对自己的解决方法不满意:我有一个程序维护一个指向基类的指针向量,并且我在那里存储了所有类型的子对象指针。现在,每个子类都有自己的方法,主程序可能会或不会调用这些方法,具体取决于对象的类型(请注意,尽管它们都大量使用基类的通用方法,因此这证明了继承的合理性)。

我发现有一个“对象标识符”来检查类类型(然后调用或不调用方法)很有用,这已经不是很漂亮了,但这不是主要的不便之处。主要的不便之处在于,如果我想真正能够使用基类指针调用派生类方法(或者甚至只是将指针存储在指针数组中),那么需要在基类中将派生方法声明为虚拟班级。

从 C++ 编码的角度来看是有意义的.. 但这对我来说是不切实际的(从开发的角度来看),因为我计划在不同的文件中创建许多不同的子类,可能是由不同的人创建的,而我不想每次都调整/维护基类,添加虚拟方法!

这该怎么做?本质上,我要问的(我猜)是如何实现类似 Objective-C NSArrays 的东西——如果你向一个没有实现该方法的对象发送消息,那么什么都不会发生。

问候

4

4 回答 4

1

您可以执行您在 C++ 中描述的操作,但不能使用函数。顺便说一句,这有点可怕,但我想在某些情况下它可能是一种合法的方法。

这样做的第一种方法:

在基类上定义一个带有类似签名的函数boost::variant parseMessage(std::string, std::vector<boost::variant>);,也许还有一串具有通用签名的便利函数,并在基类上包含一个带有仿函数的消息查找表。在每个类构造函数中,将其消息添加到消息表中,然后 parseMessage 函数将每条消息打包到类上的正确函数中。

它又丑又慢,但它应该可以工作。

第二种方法:

在层次结构中进一步定义虚函数,因此如果要添加int foo(bar*);,首先添加一个将其定义为虚拟的类,然后确保每个想要定义的类int foo(bar*);都继承自它。然后dynamic_cast,您可以在尝试调用int foo(bar*);. 这些接口添加类可能是纯虚拟的,因此可以使用多重继承将它们混合到各个点,但这可能有其自身的问题。

这不如第一种方式灵活,并且需要实现函数的类相互链接。哦,它仍然很丑。

但大多数情况下,我建议您尝试编写 C++ 代码,例如 C++ 代码而不是 Objective-C 代码。

于 2013-03-10T08:37:22.673 回答
1

这可以通过添加某种内省功能和元对象系统来解决。本演讲元数据和 C++ 中的反射 — Jeff Tucker演示了如何使用 C++ 的模板元编程来做到这一点。

如果您不想自己实现一个,那么使用现有的会更容易,例如Qt'元对象系统。请注意,由于元对象编译器的限制,此解决方案不适用于多重继承:QObject Multiple Inheritance

安装后,您可以查询方法的存在并调用它们。手动执行此操作非常繁琐,因此调用此类方法的最简单方法是使用信号和槽机制。

还有非常相似的GObject,还有其他的。

于 2013-03-10T09:49:20.530 回答
1

而不是这个:

// variant A: declare everything in the base class
void DoStuff_A(Base* b) {
  if (b->TypeId() == DERIVED_1) 
      b->DoDerived1Stuff();
  else if if (b->TypeId() == DERIVED_2) 
      b->DoDerived12Stuff();
}

或这个:

// variant B: declare nothing in the base class
void DoStuff_B(Base* b) {
  if (b->TypeId() == DERIVED_1) 
      (dynamic_cast<Derived1*>(b))->DoDerived1Stuff();
  else if if (b->TypeId() == DERIVED_2) 
      (dynamic_cast<Derived2*>(b))->DoDerived12Stuff();
}

做这个:

// variant C: declare the right thing in the base class
b->DoStuff();

请注意,每个必须完成的东西在基础中都有一个虚拟功能。

如果您发现自己更喜欢变体 A 或 B 而不是变体 C,请停下来重新考虑您的设计。您将组件耦合得太紧,最终会适得其反。

我计划在不同的文件中创建许多不同的子类,可能是由不同的人制作的,我不想每次都调整/维护基类来添加虚拟方法!

DoStuff每次添加派生类时都可以调整,但调整Base是不行的。我可以问为什么吗?

如果您的设计不适合 A、B 或 C 模式,请展示您所拥有的,因为如今千里眼是罕见的壮举。

于 2013-03-10T11:33:48.393 回答
0

如果您是planning to create many different children classes in different files, perhaps made by different people,而且我猜您不想更改每个子类的主代码。然后我认为你需要在你的基类中做的是定义几个(不是很多)虚拟函数(具有空实现)但是这些函数应该用于在逻辑中标记它们被称为“AfterInsart”的时间或“BeforeSorting”等。
通常在逻辑中你希望派生类执行自己的逻辑的地方并不多。

于 2013-03-10T10:43:36.547 回答