我已经为这个设计问题苦苦挣扎了一段时间。我将尽我所能解释我正在尝试做什么以及我所看到的各种方法,我正在尝试什么以及为什么。
我在一个科学计算环境中工作,我反复处理相同类型的对象。想象一个包含太阳系的星系,每个太阳系都包含行星系统,每个行星系统都包含卫星。为此,我认为这种情况是一种“有”的情况,因此我使用组合来让银河系进入它的太阳系,让每个太阳系进入可以进入它们的卫星的行星系统:每个类别作为自己的班级。
通常情况下,我正在处理的各种问题包含有关这些对象的不同类型的数据。而且,随着不同类型的数据可用,我可以对我的对象做某些事情。所以,当我有可用的数据类型 1 时,我创建了以下类
class GalaxyOne { /* … */ };
class SolarSystemOne { /* … */ };
class PlanetOne{ /* … */ };
class MoonOne{ /* … */ };
当我有可用的数据类型 2 时,我创建
class GalaxyTwo { /* … */ };
class SolarSystemTwo { /* … */ };
class PlanetTwo{ /* … */ };
class MoonTwo{ /* … */ };
每个类的复合方面是通过使用容器变量来处理的,例如包含指向所包含类的指针的向量。例如,在每个 Galaxy 类中都可以找到。
class GalaxyTwo{ /* … */
protected:
std::vector<SolarSystemTwo*> solarSystems;
/* … */
};
当我想将类组合成高阶类时,困难就来了。
class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo{
/* Additional methods */
};
但是,这会在 solarSystems 向量中产生一个模糊问题,因为 GalaxyOneTwo 将具有来自 GalaxyOne 和 GalaxyTwo 的版本。此外,它继承的向量包含指向非 SolarSystemOneTwo 类型对象的指针,这将是必需的。所以,我想我可以创建一个模板类,我的所有对象都从我放置所有容器变量的地方继承。
template<MoonT,PlanetT,SolarSystemT>
class PrimitiveGalaxy {
private:
std::vector<SolarSystemT*> solarSystems
};
class GalaxyOne: public PrimitiveGalaxy <MoonOne,PlanetOne,SolarSystemOne>{
/* No longer defining any container variables for composition */
};
这种方法非常适用于那些基本的 Galaxy 类型(GalaxyOne 和 GalaxyTwo)。然而,每当我尝试创建组合星系类型时,我都会遇到各种模棱两可的问题。
class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo, public PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{
/* … */
};
如果我在 GalaxyOneTwo 中定义的任何方法中使用 solarSystems,我会感到模棱两可,因为它被定义了三次,一次是通过 GalaxyOne 和 GalaxyTwo 的每个继承版本,第三次是通过 GalaxyOneTwo。
我可以通过具体和使用来摆脱这种歧义
PrimitiveGalaxy::solarSystems
每次都引用正确的向量,但这是不可取的,因为它需要大量额外的输入和语法。
我考虑过在每个星系类型和原始星系之间使用友谊,但这需要类似程度的冗长写作。
我有一种预感,命名空间可以简化我的代码编写,但我不确定如何定义命名空间,以便在为 GalaxyOneTwo 定义的命名空间中,对 solarSystems 的任何引用都是对 PrimitiveGalaxy::solarSystems 的引用
编辑:
请注意,GalaxyOne 和 GalaxyTwo 之间的唯一区别不是 solarSystems 中包含的类的类型。由于每个类别处理与星系相关的不同数据,因此存在许多差异。因此,我创建了不同的类,这些类将具有不同的状态变量、用于这些状态变量的 getter 和 setter,以及用于计算和打印数据的方法。solarSystems 是给我带来问题的功能的一个示例,因此这就是我在这里所描述的。创建 GalaxyOneTwo 时,它将使用用于 GalaxyOne 和 GalaxyTwo 的相同数据,因此我想继承它们的所有变量和方法。而且因为数据可以以不同的方式组合,我需要在 GalaxyOneTwo 中为此创建新的方法。这些是导致我使用继承的许多差异中的一些。话虽如此,允许组合的容器变量给我带来了问题。在每个 solarSystem 类中都会有一个类似的向量,让他们可以访问他们的行星,依此类推。
编辑:
对于一个专门针对我的设计哲学的问题(而不是这个问题强调试图解决我当前的设计尝试),请参阅以下链接: Guidance in created design for multiple-inheritance composite classes in c++