如何在C++;? 我试图解决一个C++中涉及并行继承的问题。关于这一点,我发现最近的一个问题是,但它并不能完全回答我的问题

如何在C++;? 我试图解决一个C++中涉及并行继承的问题。关于这一点,我发现最近的一个问题是,但它并不能完全回答我的问题,c++,design-patterns,C++,Design Patterns,我有一个由三个类组成的模型:model、Trainer、InstanceProcessor(IP),分别包含模型数据、训练函数和模型处理代码。现在我有了这个模型的大约10个不同版本,有很多代码重叠,但也有一些差异,创建了某种形式的并行继承: Model - ModelA, ModelB, ModelC, ... Trainer - TrainerA, TrainerB, TrainerC IP - IPA, IPB, IPC 在代码主体中,我使用Model*指针来访问特定的模型,具体取决于解析

我有一个由三个类组成的模型: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)

我怀疑有一种更优雅的方法来实现这一点(使用模板/接口?),我想知道是否有人能为我指出正确的方向?谢谢


编辑:为了从下面的答案中澄清一点,其中一个复杂性在于,我希望培训师课程有一个函数basic_train():


现在,根据所使用的培训师类型,创建相应的IP。该函数的其余部分不会从TrainerA更改为TrainerB实例。

用更抽象的术语来说:您有一组类,这些类在继承方面已经固定,并且您希望根据用例使它们的行为有所不同

在这种情况下,依赖项注入策略通常会有所帮助:您可以对每个方法调用执行此操作,也可以在创建对象时确定

在第一种情况下,作为参数传入更改方法行为的内容(见下文)

在第二种情况下,将该参数传递给构造函数,对象必须存储该“某物”


“something”可以简单到一组固定的值(例如enum),也可以是回调/函子/lambda或对象。选择任何合适的,关键是它可以改变对象的行为,即使它们都属于同一类。

基本上强制转换是不好的,因为它很脆弱(你会忘记在应该更新代码的时候更新代码)。相反,您应该利用多态性。我想您可能想看看,这可能符合您最初使用接口的想法。

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

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

这将引导您找到一个使用模式的可行解决方案。主应用程序将获得一个“工厂工厂”这可以根据传入的内容为它提供一个
FactoryA
FactoryB
FactoryC
。每个
FactoryX
生成
ModelX
TrainerX
IPX
对象,将它们作为它们的公共超类呈现给主程序(即
型号
培训师
,以及
IP


然而,在工厂的内部,实现对象是根据其“对应对象”的知识创建的的确切类型。例如,当
ModelA
配置了
Trainer
时,它不接受
Trainer
类型的对象-它得到
TrainerA
。因为
FactoryA
知道它创建的对象之间的依赖关系,所以它提供正确类型的对象没有问题。同时主程序不知道这个专门化,并且部分(<代码>模型A <代码> >代码> TimeRea/C++ >和 IPA<代码>对泛化的概念没有多大的了解。我想它们可能不是您在这里所需要的。谢谢,我刚刚阅读了访问者模式。这可能对我的问题的各个方面都有效。出于好奇,使用模板解决这个问题的方法是什么样的?我对模板有模糊的理解,但不太确定在这种情况下如何使用它们(现在编辑问题以使其更清晰)。根据您更新的问题,越来越难看到模板如何帮助您。它们确实是一个很好的工具,但不一定能解决此问题。在您进行功能培训的情况下,它们可能会有所帮助(培训师和培训师),您需要能够传递TrainerA和TrainerB,但它们不是通过继承连接的,而是有一些方法具有相同的名称和参数。然后,在train()中,您可以调用trainer.foo(5),即使TrainerA和TrainerB没有连接,这也会起作用(除了外观相似的方法,因此被称为“duck typing”)。谢谢你的评论,但我认为我的问题比这更复杂。行为
Trainer::basicTraining() {
    ...
    IP* ip = new IP(some args);
    ip->doStuff();
    ...
}