在c ++中解决涉及多继承和复合类的设计

Phi*_*eme 7 c++ templates composite multiple-inheritance ambiguity

一段时间以来,我一直在努力解决这个设计问题.我将尽我所能来解释我正在尝试做什么以及我所看到的各种接近,我正在尝试什么以及为什么.

我在科学计算环境中工作,在那里我反复处理相同类型的对象.想象一个包含太阳系的星系,每个太阳系都包含行星系统,每个行星系统都包含卫星.为此,我将这种情况视为一种"有"的情况,因此我使用组合来让银河系进入其太阳系,并且每个太阳系都可以进入可以进入卫星的行星系统:每个类别是自己的阶级.

通常情况下,我正在处理的各种问题包含有关这些对象的不同类型的数据.而且,随着不同类型的数据变得可用,我可以使用我的对象做某些事情.所以,当我有数据类型1可供我使用时,我创建以下类

class GalaxyOne { /* … */ };
class SolarSystemOne { /* … */ };
class PlanetOne{ /* … */ };
class MoonOne{ /* … */ };
Run Code Online (Sandbox Code Playgroud)

当我有数据类型2可供我使用时,我创建

class GalaxyTwo { /* … */ };
class SolarSystemTwo { /* … */ };
class PlanetTwo{ /* … */ };
class MoonTwo{ /* … */ };
Run Code Online (Sandbox Code Playgroud)

每个类的复合方面通过使用容器变量来处理,例如包含指向所包含类的指针的向量.例如,在每个Galaxy类中都可以找到.

class GalaxyTwo{ /* … */
protected:
std::vector<SolarSystemTwo*> solarSystems;
/* … */
};
Run Code Online (Sandbox Code Playgroud)

当我想将类组合成高阶类时,困难就出现了.

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo{
/* Additional methods */
};
Run Code Online (Sandbox Code Playgroud)

然而,这会在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 */
};
Run Code Online (Sandbox Code Playgroud)

这种方法非常适用于那些基本的Galaxy类型(GalaxyOne和GalaxyTwo).但是,每当我尝试创建组合星系类型时,我都会遇到各种各样的歧义.

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo, public     PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{
    /* … */
};
Run Code Online (Sandbox Code Playgroud)

如果我在GalaxyOneTwo中定义的任何方法中使用solarSystems,我会产生歧义,因为它定义了三次,一次是通过GalaxyOne和GalaxyTwo的每个继承版本,第三次是通过GalaxyOneTwo.

我可以通过具体和使用来消除这种模糊性

PrimitiveGalaxy :: solarSystems

每次引用适当的向量,但这是不可取的,因为它需要大量的额外输入和语法.

我曾考虑过在每个星系类型和原始星系之间使用友谊,但这需要类似的冗长写作.

我有一种预感,命名空间可能会简化我的代码编写,但我不确定如何定义命名空间,以便在为GalaxyOneTwo定义的命名空间内,对solarSystems的任何引用都是对PrimitiveGalaxy :: solarSystems的引用

编辑:

请注意,GalaxyOne和GalaxyTwo之间的唯一区别不在于solarSystems中包含的类的类型.由于每个班级都处理与银河系相关的不同数据,因此存在许多差异.因此,我创建了不同的类,这些类将具有不同的状态变量,用于那些状态变量的getter和setter以及计算和打印数据的方法.solarSystems就是这个功能的一个例子,它给我带来了问题,因此这就是我在这里所描述的.当创建GalaxyOneTwo时,它将使用与GalaxyOne和GalaxyTwo相同的数据,因此我想继承它们的所有变量和方法.因为数据可以以不同的方式组合,我需要在GalaxyOneTwo中为它创建新的方法.这些是导致我使用继承的许多差异中的一些.话虽这么说,容器变量允许组合给我带来问题.在每个solarSystem类中,将有一个类似的向量,允许他们访问他们的行星,依此类推.

编辑:

对于一般专门针对我的设计理念的问题(与强调尝试解决当前设计尝试的问题相反),请参阅以下链接: 在c ++中为多继承复合类创建设计的指导

Con*_*lis 1

也许您可以更改数据模型来实现基于组件的东西。每个组件都可以包含您提到的不同类型的相同状态信息。你可以继承虚函数

class Galaxy
{
  // galaxy information

  // Virtual functions shared among galaxies
  virtual void sharedGalaxyFunction() = 0;

  // Vector containing all solar systems in this galaxy
  std::vector<SolarSystem*> solarSystems_;
};

class SolarSystem
{     
  // solar system info

  // Virtual functions shared among all solar systems
  virtual void sharedSolarSystemFunction() = 0;

  // Vector containing planets
  std::vector<Planets*> planets_;
};

// etc for planets...
Run Code Online (Sandbox Code Playgroud)

然后,您可以继承不同类型的太阳系或星系来创建特殊情况并填写虚拟函数调用

class CoolSolarSystem : public SolarSystem
{
  // Special variables

  // Fill in the virtual function
  void sharedSolarSystemFunction();
};
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用指向特殊类型的指针填充不同基本类型内的容器。如果虚拟函数调用处理足够的信息,您应该能够避免转换回特殊类型。