0

我打算将此问题作为与我在以下链接中找到的问题相关的更笼统的问题:

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

我正在使用与 Galaxies 相关的数据集。每个星系的数据将包含有关星系的太阳系、每个太阳系行星和每个行星卫星的信息。

复合要求:

仅凭这一点,我想我需要使用复合类设计,在其中为银河系、太阳系、行星和卫星创建一个类。除了这些容器变量的适当成员 getter 和 setter 函数之外,galaxy 类将包含成员容器变量,这些变量包含指向太阳系、行星和卫星的指针。太阳系将有一个类似设计的成员容器变量,其中包含指向包含的行星和卫星的指针,以及 getter 和 setter,等等。

多重继承要求:

我为这些类中的每一个使用的输入数据类型不是恒定的。有时我有类型 1 的数据,有时可能是类型 2 的数据。我为任何给定项目所拥有的不同类型的数据可能会随着时间的推移而改变。为了避免拥有一个异常增长的星系类,它为每个项目以及所有旧的(并且可能在当前项目中未使用的)可用的数据类型获取新的成员变量和函数,我想打破星系,solarSystem ,行星和月球类上升为相关的类,每个类专门处理一组数据。

因此,如果我考虑我可用的两个可能的数据集,data1 和 data2,我可以选择为每个数据集创建每个类的特定版本。

我喜欢这种方法,因为如果我有一个需要结合 data1 和 data2 的新项目,我可以为从之前的两种相关类型继承的星系、太阳能系统、行星和月球类创建新类。类似于以下内容。

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo { /* . . .  */ };
class SolarSystemOneTwo: public SolarSystemTwo, public SolarSystemOne{ /* . . . */};
class PlanetOneTwo: public PlanetTwo, public PlanetOne{ /* . . . */ };
class MoonOneTwo: public MoonTwo, public MoonOne{ /* . . . .*/};

这使我可以访问处理 data1 和 data2 的所有变量和方法,然后我可以进一步定义变量和方法来处理由 data1 和 data2 组合产生的新属性。

问题:

这些设计思想、复合需求和多重继承需求中的每一个对我来说都非常有效。但是,我真的很想同时使用两者。两者都使用的困难在于 GalaxyOne 中那些可以访问 SolarSystemOne 指针的容器变量对 GalaxyOneTwo 没有用处,因为 SolarSystemOne 中的指针类型不能访问 SolarSystemOneTwo 的成员函数。

可能的解决方案:

模板基类- 创建一个模板基类 PrimitiveGalaxy、PrimitiveSolarSystem、PrimitivePlanet、PrimitiveMoon,其中包含所有容器变量以及所有其他类继承的相关 getter 和 setter。这是我在上面发布的链接中使用的方法,可以在那里找到它的问题。

虚拟基类- 有人提议我创建一个基类,其中包含所有类型的星系、太阳系、行星和卫星的所有共享功能。这将包括指向相关指针的容器变量以及它们的 getter 和 setter。通过这样做,指针可以用来指向每种类型的基类,只要基类型包含所有必要的后来定义的函数的虚函数,那么我就可以避免将指针转换为更复杂的类型。

我对这种方法的担忧是,它不仅需要为派生类中的每个新函数在基类中编写虚函数,而且并非每个派生类都会在基类中定义每个虚函数。

到目前为止,上述可能的解决方案是我目前唯一理解得足以发布的解决方案。

我想要一个解决方案,它允许灵活的代码,不需要复杂的语法,也不需要每一个不断增长和难以管理的非常大的类定义系列。我的项目经常包含新类型的数据,因此我希望能够轻松地为这些新数据创建新的解析器,并能够使用 Galaxy、SolarSystem、Planet 和 Moon 类轻松地将数据包含到我的各种项目中。

4

1 回答 1

1

我能够通过使用抽象基类来解决我的问题。抽象基类包含我所有的容器变量以及适当的 getter 和 setter 变量。此外,抽象基类为将在任何派生类中使用的所有方法定义了抽象方法。这些方法被预处理器指令包围,如果还包含定义所述函数的适当头文件,则仅包含那些虚拟函数,这会阻止进一步的抽象类。

class Galaxy{
    protected:
       std::vector<SolarSystem*> solarSystems;
    public:
       void addSolarSystem(SolarSystem*);
#ifdef GALAXYONE
virtual void aGalaxyOneMethod()=0;
#endif

#ifdef GALAXYTWO
virtual void aGalaxyTwoMethod()=0;
#endif

#ifdef GALAXYONETWO
virtual void aGalaxyOneTwoMethod()=0;
#endif

enter code here

};

GalaxyOne.h

#define GALAXYONE
class GalaxyOne{
    protected:
        /*Private Variables for GalaxyOne*/
    public:
        void aGalaxyOneMethod(); //No longer abstract
};

GalaxyTwo.h

#define GALAXYTWO
class GalaxyTWO{
    protected:
        /*Private Variables for GalaxyTwo*/
    public:
        void aGalaxyTwoMethod(); //No longer abstract
};

GalaxyOneTwo.h

#define GALAXYONE
#define GALAXYTWO
#define GALAXYONETWO
class GalaxyOneTwo: virtual public GalaxyOne, virtual public GalaxyTwo{
    protected:
        /*Private Variables for GalaxyOneTwo*/
    public:
        void aGalaxyOneTwoMethod(); //No longer abstract
};

该方案允许创建 GalaxyOneTwo 类型的对象并将其存储在 Galaxy 的指针中,并且仍然可以访问适当的函数。SolarSystems、Planets 和 Moons 使用了类似的策略

于 2013-03-04T19:30:42.290 回答