0

この質問は、次のリンクにある私の質問に関連する、より一般的な質問になる予定です。

C ++で複数の継承と複合クラスを含む設計を解決する

銀河に関連するデータセットを扱っています。各銀河に関するデータには、銀河の太陽系、各太陽系の惑星、および各惑星の衛星に関する情報が含まれます。

複合要件:

これだけでも、銀河、太陽系、惑星、月のクラスを作成する複合クラス設計を使用する必要があると思います。銀河クラスには、太陽系、惑星、月へのポインターを含むメンバー コンテナー変数と、それらのコンテナー変数の適切なメンバー getter および setter 関数が含まれます。太陽系にも同様に設計されたメンバ コンテナ変数があり、含まれている惑星と月へのポインタがゲッターとセッターで含まれ、惑星についても同様です。

多重継承要件:

これらの各クラスで使用する入力データの型は一定ではありません。タイプ 1 のデータを持っている場合もあれば、タイプ 2 のデータを持っている場合もあります。特定のプロジェクトで使用するさまざまな種類のデータは、時間の経過とともに変化する可能性があります。各プロジェクトで利用可能なデータのタイプではないタイプごとに新しいメンバー変数と関数を取得する、巨大に成長する銀河クラスを持つことを避けるために、すべての古い (そしておそらく現在のプロジェクトでは使用されていない) 銀河、solarSystem を壊したい、惑星、および月のクラスは、それぞれが特定のデータ セットを処理するために特化された関連するクラスに分類されます。

したがって、利用可能な 2 つのデータ セット (data1 と data2) を考えると、データ セットごとに各クラスの特定のバージョンを作成することを選択できます。

私がこのアプローチを気に入っているのは、data1 と data2 の組み合わせを必要とする新しいプロジェクトがある場合、以前の両方の関連タイプから継承する Galaxy、solarySystem、planet、および moon クラスの新しいクラスを作成できるためです。次のようなもの。

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 を処理するためのすべての veriable とメソッドにアクセスでき、data1 と data2 の組み合わせから生じる新しいプロパティを処理するための変数とメソッドをさらに定義できます。

問題:

これらの設計アイデア、複合要件、および多重継承要件のそれぞれは、私にとっては単独でうまく機能しています。でも、本当は両方使いたい。両方を使用することの難しさは、SolarSystemOne のポインターへのアクセスを提供する GalaxyOne 内のコンテナー変数が、GalaxyOneTwo には役に立たないことです。これは、SolarSystemOne のポインターの型が SolarSystemOneTwo のメンバー関数へのアクセスを提供しないためです。

可能な解決策:

テンプレート 基本クラス - テンプレート基本クラス PrimitiveGalaxy、PrimitiveSolarSystem、PrimitivePlanet、PrimitiveMoon を作成します。これには、すべてのコンテナー変数と、関連する 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 に答える