3

我正在尝试解决涉及 C++ 中的并行继承的问题。我为此找到的最接近的问题是并行继承树,其中一棵树的类具有另一棵树的类的容器,但它并不能完全回答我的问题。

我有一个模型,由三个类组成:Model、Trainer、InstanceProcessor (IP),分别包含模型数据、训练函数和模型处理代码。现在我有这个模型的大约 10 个不同版本,有很多代码重叠但有些差异,创建了某种形式的并行继承:

Model - ModelA, ModelB, ModelC, ...
Trainer - TrainerA, TrainerB, TrainerC
IP - IPA, IPB, IPC

在代码主体中,我使用 Model* 指针根据解析的参数访问特定模型。

Model 和 Trainer 都需要多个短暂的 IP 实例,Model 还需要一个永久的 Trainer 实例。

我当前的实现使用三个带有一些虚函数的基类,然后对从这些基类继承的特定类进行建模。这需要我使用大量的铸造(例如,从 model.h 中的 Trainer* trainer 到 TrainerA 以满足特定需求)。

我怀疑有一种更优雅的实现方式(使用模板/接口?),并且想知道是否有人可以指出我正确的方向?谢谢!


编辑:为了从下面的答案中澄清一点,其中一个复杂之处在于我想要例如。Trainer 类具有函数 basic_train():

Trainer::basicTraining() {
    ...
    IP* ip = new IP(some args);
    ip->doStuff();
    ...
}

现在在哪里创建适当的 IP,具体取决于使用的培训师的类型。该函数的其余部分不会从 TrainerA 更改为 TrainerB 实例。

4

3 回答 3

2

当两个独立层次结构的成员紧密耦合时,继承不会给你带来太多好处。继承承诺混合匹配策略应该是可能的(即使用ModelAwithTrainerB和 an IPC),而实际上这不起作用。

然而,需要意识到的一件非常重要的事情是模型、训练器和 IP 彼此呈现的界面可能与它们共同呈现给主应用程序的界面不同:主应用程序将它们视为一组统一的对象,而模型/培训师/IP的每个子组(即ABC)将同一组的成员视为高度专业化的。因此,尽管继承可能对继承层次结构的各个部分不利,但可能对主程序有利。

这将引导您找到使用抽象工厂模式的可行解决方案。主应用程序得到一个“工厂工厂”,它可以给它一个FactoryA,FactoryBFactoryC基于它传入的任何内容。每个都FactoryX产生ModelX,TrainerX和对象,将它们作为它们的公共超类(即,和)IPX呈现给您的主程序。ModelTrainerIP

然而,在工厂的内部,实现对象是在知道其“对应对象”的确切类型的情况下创建的。例如,当ModelA配置了 a时Trainer,它不接受类型的对象Trainer- 它得到TrainerA. 由于FactoryA知道它创建的对象之间的依赖关系,因此它可以毫无问题地提供正确类型的对象。同时,主程序不知道这种特化,部分(ModelATrainerA、 和IPA)对泛化知之甚少。

于 2013-10-16T20:07:26.347 回答
1

基本上铸造很糟糕,因为它很脆弱(当你应该更新代码时你会忘记更新代码)。相反,您应该利用多态性。我想你可能想看看访问者模式,这可能符合你最初使用接口的想法。

于 2013-10-16T19:56:27.480 回答
0

用更抽象的术语来说:您有一组在继承方面已经固定的类,并且您希望根据用例使它们中的每一个表现不同。

在这种情况下,大多数时候依赖注入策略会有所帮助:您可以为每个方法调用执行此操作,或者您可以在创建对象时决定它。

在第一种情况下,您传入 - 作为参数 - 改变方法行为的东西(见下文)。

在第二种情况下,您将该参数传递给构造函数,并且对象必须存储该“东西”。

“某物”可以像一组固定值(例如枚举)一样简单,也可以是回调/仿函数/lambda 或对象。选择任何舒适的东西,关键是它可以改变对象的行为,即使它们都是同一个类。

于 2013-10-16T19:50:46.040 回答