0

いくつかのアルゴリズムを使用してオブジェクトの範囲を概算するために、C++ で物理プログラムを作成しています。具象メソッドと抽象メソッドの両方を含む基本クラス Simulation を宣言しました。(たとえば、範囲を概算する関数は純粋な仮想ですが、次の位置を取得する関数は具体的です。これはアルゴリズムに関係なく同じです。) これらの具体的なメソッドを定義するために、基本クラスですべての変数を宣言しました。同じように。派生クラスでは、基本クラスの抽象メソッドと新しいアルゴリズム固有のメソッドの両方を定義します。これには、基本クラスと派生クラスの両方でメンバーを定義する必要があります。

問題は、基本クラスで定義された具体的なメソッドが、派生クラスで定義されたオーバーライドされたものではなく、基本クラスのメンバーにアクセスしていることです。これを行う方法はありますか、それとも私のアプローチ自体が間違っていますか?

コンストラクターにも同様の問題があります。派生クラスのコンストラクターから基本コンストラクターを呼び出すと、基本メンバーが初期化されます。

とにかく、お時間をいただきありがとうございます。私は C++ にまったく慣れていないわけではありませんが、C として使用する傾向がありました。私はオブジェクト指向の概念にあまり慣れていません。私は非常に初歩的な間違いを犯している可能性があります (または、設計上の欠陥である可能性が高い) が、派生クラスでメソッドを再定義する以外のテストで、類似したものを見つけられなかったり、肯定的な結果が得られたりしたことはありません。(これは避けるべきだと思います)

更新: メンバーを保護することはできましたが(Ozraptor に感謝します。どうやってそれを見逃したのかよくわかりません)、R Sahu の要求に従って、(現在更新された) コードの一部を投稿します。

基本クラス:

class Simulation {
 public:
  Simulation();
  Simulation(float, float, float, float, float, float, float, float, float);
  bool IsInitialized(),
       set_air_density(float),
       set_delta_time(float),
       set_drag_coefficient(float),
       set_mass(float),
       set_reference_area(float);
  float next_x_position();
  void set_next_x_position(float),
       set_next_x_velocity(float),
       set_next_y_position(float),
       set_next_y_velocity(float);
 protected:
  static const float gravitational_acceleration_;
  virtual bool SimulateRangeOrDie() = 0;
  virtual void GetNextVelocity() = 0,
               GetNextXVelocity() = 0,
               GetNextYVelocity() = 0,
               InitializeConstant() = 0;
  void GetNextPosition(),
       GetNextXPosition(),
       GetNextYPosition(),
       PushBackPositionVelocity();
  bool x_position_initialized_,
       x_velocity_initialized_,
       y_position_initialized_,
       y_velocity_initialized_;
  float air_density_,
        current_x_position_,
        current_x_velocity_,
        current_y_position_,
        current_y_velocity_,
        delta_time_,
        drag_coefficient_,
        constant_,
        mass_,
        next_x_position_,
        next_x_velocity_,
        next_y_position_,
        next_y_velocity_,
        reference_area_;
};

派生クラスの 1 つ:

class MomentumSimulation : public Simulation {
 public:
  MomentumSimulation();
  MomentumSimulation(float, float, float, float, float, float, float, float,
                     float);
  virtual bool SimulateRangeOrDie();
 private:
  virtual void GetNextVelocity(),
               GetNextXVelocity(),
               GetNextYVelocity(),
               InitializeConstant();
  void GetNextMomentum(),
       GetNextXMomentum(),
       GetNextYMomentum(),
       Initialize(),
       InitializeMomentum(),
       InitializeXMomentum(),
       InitializeYMomentum(),
       PushBack(),
       PushBackMomentum();
  float current_x_momentum_,
        current_y_momentum_,
        next_x_momentum_,
        next_y_momentum_;
};
4

3 に答える 3

0

各特定のアルゴリズム (各派生クラス) でオーバーライドする必要がある基本クラスのメソッドを宣言する必要がありますvirtualこのアプローチは、テンプレート メソッド パターンと呼ばれることもあります。
メンバー データに関しては、派生クラスで基本クラスの保護されたデータ メンバーにアクセスでき、多くの場合コードを記述する最速の方法ですが、これを実行する最もクリーンな方法は、基本クラスから直接メンバー データにアクセスするのではなく、このデータにアクセスまたは操作し、代わりにそれらを呼び出すメンバー関数。これは、カプセル化 OO の原則に由来します。参照:メンバー変数を保護することをお勧めしますか?

少し不自然な (C++11) 例を示すために、基本シミュレーション クラスを次に示します。

using namespace std;
using namespace chrono;

class Simulation {
  public:
  // this is the same across all simulations:
    void run() {
      recordStartTime();
      bool result = actuallySimulateStuff();
      printSimulationResult(result);
    }

  protected:
  // virtual methods should be overridden in derived classes
  // this one has to be
    virtual const string& name() const = 0;
  // this one may not be, but if you don't, the simulation isn't going tobe very interesting
    virtual bool actuallySimulateStuff() { return false; }

  // these methods, like run() above, are invariant for all inherited classes
    void recordStartTime() {
      start_time_ = system_clock::now();
    }
    const start_time_& start_time() const {
      return start_time_;
    }
    void printSimulationResult(bool result) {
      auto end_time = system_clock::now();
      auto durationInMS = duration_cast<milliseconds>(end_time - start_time_);

      cout << "Simulation: '" << name() << "'";
      cout << (result ? "Succeeded" : "Failed");
      cout  << " in " << durationInMS << "ms."; 
    }

  private:
    system_clock::time_point start_time_ {};
};

そして、ここに特定のシミュレーションクラスがあります:

class TransmogrifySimulation : public Simulation {
  protected:
  // virtual methods should be overridden in derived classes
    virtual const string& name() const {
       static const string name_ = "TransmogrifySimulation";
       return name_;
    }

    virtual bool actuallySimulateStuff() {
       // simulate transmogrification here...
       ...
       // which implies, at some point:
       someSimulationDetail();
       ...

       return result_;
    }

    void someSimulationDetail() {
       // this is a really weird, unreliable simulation
       auto currentRunTime = duration_cast<milliseconds>(system_clock::now() - start_time());
       result_ = 0 != (currentRunTime % 2);
    }

   private:
     bool result_ = false;
};

これは単なる例ですが、使用する概念に慣れたい場合は、The Definitive C++ Book Guide and Listから初心者向けガイドを入手し、少なくともクラスと継承に関連する章を読むことを強くお勧めします。

コンストラクターに関しては、カプセル化の同じ原則に従います。クラスのコンストラクターは、クラス階層のそのレベルで定義されたメンバー データの初期化を担当します。次の点に注意してください。

于 2014-03-11T03:07:41.487 に答える