2013-02-25 9 views
7

私はしばらくこの設計問題に苦労しました。私は何をしようとしているのかを説明するために最善を尽くし、様々なものが私が見たもの、私が何をしようとしているのか、そしてなぜそれに近づいたのです。C++で多重継承と複合クラスを含むデザインを解決する

私は同じ種類のオブジェクトを繰り返し処理する科学計算環境で働いています。太陽系を含む銀河を想像してみましょう。各太陽系には惑星系が含まれ、各惑星系には月が含まれています。この目的のために私は状況が「ある」状況であると考え、私は太陽系へのアクセスを銀河に与えるために構成を使用し、各太陽系は月にアクセスできる惑星系へのアクセスを取ったそれ自身のクラスです。

私が取り組んでいるさまざまな問題には、これらのオブジェクトに関するさまざまな種類のデータが含まれていることがよくあります。また、さまざまな種類のデータが利用できるようになると、私は自分のオブジェクトで特定のことを行うことができます。だから、私は私に利用可能なデータタイプ1を持っているとき、私は次のクラス

class GalaxyOne { /* … */ }; 
class SolarSystemOne { /* … */ }; 
class PlanetOne{ /* … */ }; 
class MoonOne{ /* … */ }; 

を作成し、私は私に利用可能なデータタイプ2を持っているとき、私は、各クラスの複合側面が配られる

class GalaxyTwo { /* … */ }; 
class SolarSystemTwo { /* … */ }; 
class PlanetTwo{ /* … */ }; 
class MoonTwo{ /* … */ }; 

を作成含まれるクラスへのポインタを含むベクトルなどのコンテナ変数を使用してたとえば、各ギャラクシークラス内では、1つが見つかります。

class GalaxyTwo{ /* … */ 
protected: 
std::vector<SolarSystemTwo*> solarSystems; 
/* … */ 
}; 

私がクラスを高次クラスに結合するのは難しいです。

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo{ 
/* Additional methods */ 
}; 

GalaxyOneTwoがGalaxyOneとGalaxyTwoから、それのバージョンを持っているでしょうしかし、これはsolarSystemsベクトルにおける曖昧さの問題を作成します。さらに、継承するベクトルには、必要とされるタイプの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 */ 
}; 

このアプローチは、これらの基本的な銀河の種類(GalaxyOneとGalaxyTwo)のために非常にうまく動作します。しかし、結合した銀河タイプを作成しようとすると、私はあらゆる種類のあいまいさを感じます。

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo, public  PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{ 
    /* … */ 
}; 

それは一度GalaxyOneとGalaxyTwoからそれぞれ継承バージョンとGalaxyOneTwo介して第三の時間を通して、三回定義されているので、私はGalaxyOneTwoで定義されたメソッド内solarSystemsを使用する場合、私はあいまいさを得ます。

私は特定のものと

PrimitiveGalaxy :: solarSystems

適切なベクトルを参照するために、それぞれの時間を使って、この曖昧さを取り除くことができますが、それは余分なタイピングの多くを必要とするため、これは望ましいことではありませんおよび構文。

私は各銀河タイプと原始銀河の間に友情を使うことを考えましたが、これには同様のレベルの冗長な書き込みが必要です。

私は名前空間は、コードの私の文章を簡素化することが予感を持っていますが、私はそのようなことを名前空間を定義する方法を確認していないsolarSystemsへの参照が PrimitiveGalaxy :: solarSystems

への参照であることをGalaxyOneTwoのために定義された名前空間内の

編集:

GalaxyOneとGalaxyTwoの唯一の違いは、solarSystemsに含まれるクラスの種類ではありません。各クラスは銀河に関連するさまざまなデータを扱うため、多くの違いがあります。したがって、これらの状態変数と、データを計算して印刷するメソッドに対して、異なる状態変数、ゲッター、およびセッターを持つ異なるクラスを作成します。 solarSystemsは私にこのように問題を与えている特徴の例です。これは私がここで述べたものです。 GalaxyOneTwoが作成されると、GalaxyOneとGalaxyTwoで使用されているのと同じデータが使用されるため、すべての変数とメソッドを継承したいと考えています。また、データをさまざまな方法で組み合わせることができるため、GalaxyOneTwo内で新しいメソッドを作成する必要があります。これらは相続を利用する多くの相違の一部です。それは言われている、それは私に問題を与える構成を可能にするコンテナ変数です。各solarSystemクラスの中には、惑星へのアクセスなどを与える同様のベクトルがあります。

編集:

ここで、一般的に私のデザイン哲学に特に専用の質問については(私の現在の設計の試みを解決しようとする上で、この質問の強調ではなく)次のリンクを参照してください。 Guidance in creating design for multiple-inheritance composite classes in c++

+0

GalaxyOneとは何ですか?銀河の異なる種類の銀河のコレクション、または2つの共通のインターフェイス(または実装???)? GalaxyOneTwoでどんな操作をしたいですか? –

+0

私が上記で説明したように、GalaxyOneTwoはGalaxyOneとGalaxyTwoのメンバー機能にアクセスできるだけでなく、同じデータを処理できる銀河です。伝統的に利用可能なさまざまな種類のデータより複雑なデータ分析を行うためにGalaxyOneとGalaxyTwoにのみ適用されます。 – PhiloEpisteme

+0

いいえ、私は疑問に思っています:あなたは継承を使ってモデル化しようとしていることは何ですか?銀河系と銀河系の2つに見られる太陽系のすべての種類を持つ銀河の一種?どのような操作を求めたら、私は銀河の総質量、光度、星数などを得る具体的な例を意味します。 GalaxyOneTwoがどのような複合機能を持つべきかの例を挙げると、より良い回答が得られるかもしれません。 –

答えて

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... 

あなたはその後、特別なケースを作成し、仮想関数を記入する太陽光発電システムや銀河の様々なタイプを継承する可能性は、あなたが、その後、容器を取り込むことができ

class CoolSolarSystem : public SolarSystem 
{ 
    // Special variables 

    // Fill in the virtual function 
    void sharedSolarSystemFunction(); 
}; 

呼び出しますあなたの特別な型へのポインタを持つ異なる基本型の中にあります。仮想関数呼び出しがその情報を十分に処理するならば、特別な型へのキャストバックを避けることができます。

+0

このアプローチでは、新しいデータが使用されたときに、より複雑なComposite SolarSystemクラスが構築されるため、同じ関数を何度も再定義する必要はありませんか? – PhiloEpisteme

+0

一部のCoolSolarSystemsだけが共有機能を実装している場合、これは機能しますか?私が想像しているところは、より多くの複合関数を作成するとき、私は特殊関数のケースでそれらを必要とする特殊関数を定義し、SolarSystemクラスではあとで定義する仮想関数を追加するだけです。しかし、method1では、CoolSolarSystem1だけがその機能を実装していると言います。 CoolSolarSystem2が未定義のままにしても問題ありませんか? – PhiloEpisteme

+0

関数が純粋仮想関数でない場合、それは間違いなく機能します。 "実装されていない"オブジェクトに対して関数が何もしないようにするには、基本クラスに対して単純な機能を実装する必要があります。 –

2

をI class Galaxy,1つのclass SolarSystemなどが必要です。あなたのGalaxyOne,GalaxyTwoSolarSystemOneSolarSystemTwoなどは、これらのクラスからインスタンス化されたオブジェクトとは異なります。ここで

class GalaxyOneTwo: public GalaxyOne, 
        public GalaxyTwo, 
        public PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{ 
    /* … */ 
using PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>::solarSystems; 
GalaxyOneTwo(){solarSystems.reserve(10);} 
}; 

次の3つのプライベートベクトルを持っている:私たちは、この単純なaproachを使用する方法がありません場合は

class SolarSystem { /* … */ }; 
class Planet{ /* … */ }; 
class Moon{ /* … */ }; 

class Galaxy{ /* … */ 
public: // Galaxy(...?...){for (...) {read data??; solarSystem.push_back(createSolarSystem(data)); } 
void AddSolarSystem(SolarSystem* ss){solarSystem.push_back(ss);} 
protected: 
    std::vector<SolarSystem*> solarSystems; 
    /* … */ 
}; 

....

Galaxy GalaxyOne, GalaxyTwo; 

は...あなたを見ることができます( usingを使用すると、直接アクセス可能になります)

std::vector<SolarSystemOne* > GalaxyOne::solarSystems; 
std::vector<SolarSystemTwo* > GalaxyTwo::solarSystems; 
std::vector<SolarSystemOneTwo*> solarSystems; //GalaxyOneTwo::solarSystems; 

これは必要なものですか?それを保護させる?あなたは「共通の」基底クラスのセットに抽象的に「ワン」とスタッフの「2つの」バージョン間の共通のものを必要とする enter image description here

+0

いいえ、これは当てはまりません。おそらく私は私の記述から明らかではなかった。私はそれらを扱うためにさまざまな変数とメソッドを必要とするさまざまな種類のデータを扱います。 GalaxyOneはある種のデータを扱うために作られた銀河のクラスです。GalaxyTwoは異なるデータセットを扱うため、データ処理の変数とメソッドが異なります。 GalaxyOneTwoは元の種類のデータを両方持っているので、GalaxyOneとGalaxyTwoの元の変数とメソッドが新しい変数と利用可能なデータの合成を処理するメソッドであることを望んでいます。 – PhiloEpisteme

+0

はい、私は質問があります:SolarSystemのタイプはGalaxysタイプの唯一の違いですか? GalaxyOneTwoはClas OneのSolarSystemとType TwoのSolarSystemだけを持っていますか? – qPCR4vir

+0

いいえ、それだけで違いはありません。どこに楕円があるのか​​は、他の違いがあるところです。大きな違いがあります。 GalaxyOneは一連のデータを処理し、callはdata1です。 GalaxyOneで見つけたdata1に関連する変数とメソッドがあります。 GalaxyTwoは、data1と全く同じではないdata2のセットを扱います。したがって、GalaxyTwoには他にも多くの違いがあります。 SolarSystemOneやMoonOneなどのオブジェクトを含むコンテナ変数ではない変数やメソッドには問題がありませんので、それらを含めませんでした。 – PhiloEpisteme

0

class GalaxyCommon { 
    // all the common stuff between GalaxyOne and GalaxyTwo including 
    std::vector<SolarSystemCommon *> solarSystems; 
    ... 
}; 

class GalaxyOne : public virtual GalaxyCommon { 
    // all the stuff that is unique to model One 
}; 

class GalaxyTwo : public virtual GalaxyCommon { 
    // all the stuff that is unique to model Two 
}; 

class GalaxyOneTwo : public virtual GalaxyOne, public virtual GalaxyTwo { 
    // should be complete 
}; 

virtualの使用 - 複数の継承を正しく処理するために必要です。

+0

私はすでに共通のものを抽象化しているので、PrimitiveGalaxyを使用しています。 PrimitiveGalaxyはテンプレートクラスであり、各クラスから継承されるたびに、関連するテンプレート用に別のバージョンが作成されるため、私の問題は実際にはダイアモンドの問題の1つではありません。私の挑戦は、GalaxyOneTwoからPrimitiveGalaxyのメンバーを参照する際のあいまいさを除去する効率的な方法を見つけることです。 – PhiloEpisteme

0

私はあなたの質問の権利を理解するのであれば:

  1. をそれらの間の共通点は全く何もないことができます銀河のいくつかの種類があります。
  2. 太陽系と惑星系についても同じことが言えます。
  3. これらの異なるタイプのコレクションを結合したいが、そのタイプの基本的なメソッドに完全にアクセスすることができます。

あなたの銀河がある。これはboost::any

のためのケースのように聞こえるだから今:

#include <list> 
#include <boost/any.hpp> 
typedef std::vector<boost::any> collection; 
class Galaxy 
{ 
    collection SolarSystems; 
    public: 
    ...methods... 
}; 
class SolarSystem 
{ 
    collection PlanetarySystems; 
    public: 
    ...methods... 
}; 
class PlanetarySystem 
{ 
    collection Moons; 
    public: 
    ...methods... 
}; 

勿論、これは本当に何もしませんが、グループにあなたを認めていません。役に立つもの(メソッドを呼び出す)を行うためには、タイプを検出し、そのタイプにキャストしてから、必要なコードを実行する必要があります。

しかし、これでできることは、さまざまな種類のオブジェクトをグループ化することです。これは、GalaxyOneTwoを使用していると思います。あなたがそれを行う方法についてはmore informationです。